Showing posts with label ListView. Show all posts
Showing posts with label ListView. Show all posts

Wednesday, October 4, 2017

ListView with images android

Bạn muốn tạo một ListView có nhiều ảnh khác nhau ở mỗi dòng, kiểu như bảng lịch thi đấu bóng đá. Ta phải dùng custom Adapter.
Hãy tạo một class bất kỳ, khai báo vào file Androidmanifest.xml.
Layout của class này chỉ có một listView
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
  android:background="#ffffff"
    android:orientation="vertical" >
<ListView
        android:id="@+id/list"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="2dp"      
        android:dividerHeight="1px"
        android:lineSpacingExtra="-8dp"
        android:singleLine="true"
        android:textColor="#00F" >
    </ListView>
</LinearLayout>
Tạo một class có tên customadapter.
public class customadapter extends ArrayAdapter<String> {
          private final Activity context;      
          private final Integer[] imgid;
          private final Integer[] imgid2;
          private final String[]  item;
          private final String[]  item2;
          private final String[]  item3;
          public customadapter(Activity context, String[] item, String[] item2, String[] item3, Integer[] imgid,Integer[] imgid2) {
              super(context,R.layout.lit,item);
              // TODO Auto-generated constructor stub             
              this.context=context;
              this.item=item;
              this.item2=item2;
              this.item3=item3;
              this.imgid=imgid;
              this.imgid2=imgid2;
          }        
          @SuppressLint({ "ViewHolder", "InflateParams" })
          public View getView(int position,View view,ViewGroup parent) {
              LayoutInflater inflater=context.getLayoutInflater();
View rowView=inflater.inflate(R.layout.lit, null,true);
             
TextView txtTitle = (TextView) rowView.findViewById(R.id.text1);
TextView txtTitle2 = (TextView) rowView.findViewById(R.id.text2);
TextView txtTitle3 = (TextView) rowView.findViewById(R.id.text3);
ImageView imageView = (ImageView) rowView.findViewById(R.id.im);       
ImageView imageView2 = (ImageView) rowView.findViewById(R.id.im2);          
txtTitle.setText(item[position]);
txtTitle2.setText(item2[position]);
txtTitle3.setText(item3[position]);
imageView.setImageResource(imgid[position]);
imageView2.setImageResource(imgid2[position]);           
     return rowView;             
          };
     }
Nhập các thư viện cần dùng vào.
Copy các image cần dùng vào thư mục drawable dưới res.
Trong class có listView, khai báo adapter, các mảng cần dùng lên trên dòng Override.
ListView lv;
private ArrayAdapter<String> adapter;
     String[] ten = { "France", "Albania", "Romania", "France", "Switzerland", "Romania" };
     String[] ten2 = { "Romania", "Switzerland", "Switzerland", "Albania",
              "France", "Albania" };
     String[] kq = { "1-0", "2-1", "2-3", "3-3", "1-4", "3-2" };
     Integer[] mg = new Integer[] { R.drawable.phap, R.drawable.anba,
              R.drawable.roma, R.drawable.phap, R.drawable.thuysi,
              R.drawable.roma };
     Integer[] mg2 = new Integer[] { R.drawable.roma, R.drawable.thuysi,
              R.drawable.thuysi, R.drawable.anba, R.drawable.phap,
              R.drawable.anba };
Tiếp theo tham chiếu địa chỉ và set listView với adapter từ class customadapter đã tạo.
lv = (ListView) findViewById(R.id.list);
lv.setChoiceMode(ListView.CHOICE_MODE_SINGLE); 
     adapter= new customadapter(this,ten,kq,ten2,mg,mg2);
         
     lv.setOnItemClickListener(new OnItemClickListener() {
              @Override
     public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
                        long arg3) {
                   // int sodong = arg2;
                   //dem = 1;
              }
          });
          lv.setAdapter(adapter);

Chạy thử để thấy listView đã có các ảnh, chữ như ta set trong mảng.


Trang trí màu nền nổi cho ListView

Bạn muốn đổ nền màu trang trí cho ListView để nó trông như sau.

Hãy tao một file xml có tên back3 trong thư mục drawable
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <gradient
        android:startColor="#EFEFEF"
        android:endColor="#989898"
        android:type="linear"
        android:angle="270"
    />
</shape>
Sau đó trong thư mục layout, tạo một file xml có tên li2 để tô màu chữ, thêm icon vào cho ListView.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="42sp" 
    android:background="@drawable/back3" 
    android:orientation="horizontal" > 
    <TextView
        android:id="@+id/text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_marginLeft="5sp"       
        android:textColor="#0000aa"
        android:textSize="18sp" />

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentEnd="true"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
        android:layout_marginRight="10dp"
        android:contentDescription="@null"
        android:src="@drawable/ten" />

</RelativeLayout>
Background của file trên chính là lấy từ file back3 trong drawable. Bây giờ khi set adapter cho ListView, bạn dùng dòng sau.
adapter=new ArrayAdapter<String>(this,R.layout.li2,R.id.text, array);


Kết quả ListView đã có màu xám bạc trông như nổi.

Xóa mất hẳn dòng Listview.

Sau khi đã biết cách ghi và đọc dữ liệu, bây giờ ta sẽ xóa dòng ListView mà sau đó mở lại class thì nó đã mất dòng đó chứ không hiện lại toàn bộ như trước.
Để làm việc này, ta nhớ lại đã thực hành xóa dòng Listview trong class forth, hoặc class của bạn thì bạn sẽ lại làm ở đó.
Ta sẽ biến mảng qua thành một file có tên danhsach.txt mà từng dòng của nó là từng phần tử của mảng.
Mục đích là để sang bên class forth có xóa dòng, ta sẽ dùng file này để xóa, khi xóa thì ta lưu file mới để mỗi khi bật ra class forth nó không load lại toàn bộ mảng nếu ta cứ dùng cái mảng quả cố định.
Và chú ý là tại class MainActivity này ta chỉ ghi file danhsach.txt duy nhất một lần đầu tiên. Nếu lần nào mở ra cũng ghi, ta sẽ lại có liên tiếp các phần tử quả nối đuôi vào danh sách.
Để làm việc này, trước khi ghi ta sẽ đọc file danhsach.txt ra thành mảng, nếu mảng rỗng tức là chưa có file đó thì ta mới ghi. Còn nếu đã có dữ liệu thì ta không ghi nữa.
Bắt đầu làm.
Hãy khai báo một ArrayList có tên kiemtra.
ArrayList<String> kiemtra = new ArrayList<String>();
Sau đó đọc file danhsach.txt.
String line = "";
          try {
FileInputStream In = openFileInput("danhsach.txt");
InputStreamReader inputReader = new InputStreamReader(In);
BufferedReader BR = new BufferedReader(inputReader);
          while ((line = BR.readLine()) != null) {
          kiemtra.add(line);
          }
          BR.close();
          } catch (IOException e) {
              e.printStackTrace();
          }
Tiếp theo kiểm tra độ dài của mảng xem, nếu =0 tức chưa có file danhsach, ta mới ghi dữ liệu vào.
if(sophantu==0){
         try {
FileOutputStream fos = openFileOutput(
                        "danhsach.txt", Context.MODE_APPEND);
OutputStreamWriter osw = new OutputStreamWriter(
                        fos);
          for (int i = 0; i < qua.length; i++) {
          osw.append(qua[i] + "\n");
              }
              osw.flush();
              osw.close();
          } catch (FileNotFoundException e) {
              // TODO Auto-generated catch block
              e.printStackTrace();
          } catch (IOException e) {
              // TODO Auto-generated catch block
              e.printStackTrace();
          }
          }
Nhập các thư viện cần dùng vào. Sửa lệnh ở nút b2 để nó mở sang đúng class có ListView sẽ xóa dòng, tức class forth.


Tại class forth, khai báo mảng qua2 để đọc các phần tử trong file danhsach.txt vào nó. Nếu trước đó bạn đã thực hành add các phần tử quả vào nó rồi thì giờ bỏ hết đi, rào thành comment, đảm bảo qua2 là rỗng.
Lệnh đọc file danhsach.txt ra mảng như sau:
String line = "";
try {
FileInputStream In = openFileInput("danhsach.txt");
InputStreamReader inputReader = new InputStreamReader(In);
BufferedReader BR = new BufferedReader(inputReader);
          while ((line = BR.readLine()) != null) {
          qua2.add(line);
          }
          BR.close();
          } catch (IOException e) {
          e.printStackTrace();
          }   
Ta tạo một file xml có tên li3 trong thư mục layout, trong đó có một checked textView.
<?xml version="1.0" encoding="utf-8"?>
<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/text"
    android:layout_width="fill_parent"
    android:layout_height="46dp"
    android:checkMark="@android:drawable/btn_radio"
    android:gravity="center_vertical"
    android:paddingLeft="2dip"
    android:paddingRight="2dip"
    android:textAppearance="?android:attr/textAppearanceLarge"
    android:textColor="#000080"
    android:textSize="17sp" />

Mục đích để ListView có nút chọn nhìn bắt mắt hơn, sau đó set adapter.
adapter=new ArrayAdapter<String>(this,R.layout.li3,R.id.text, qua2);
Trong nút xóa, ta kiểm tra xem đã chọn dòng chưa, nếu chọn rồi ta xóa dòng, bỏ phần tử cần xóa trong mảng đi, xóa file danhsach, đồng thời lấy mảng đã bỏ phần tử ghi lại thành file cũng có tên là danhsach.txt. Kèm theo đó là thông báo đã xóa dòng ra màn hình.
Toàn bộ code nút xóa bây giờ như sau.
b1.setOnClickListener(new View.OnClickListener() {
     @Override
     public void onClick(View v) {
     if (dem == 0) {
Toast.makeText(forth.this, "Bạn chưa chọn dòng",
                                  Toast.LENGTH_SHORT).show();
} else {
SparseBooleanArray checked = lv.getCheckedItemPositions();
          for (int i = 0; i < lv.getCount(); i++) {
              if (checked.get(i) == true) {
                   qua2.remove(i);
                   }
              adapter.notifyDataSetChanged();
          }
          lv.clearChoices();
          deleteFile("danhsach.txt");
     try {
FileOutputStream fos = openFileOutput("danhsach.txt",
                                      Context.MODE_APPEND);
OutputStreamWriter osw = new OutputStreamWriter(fos);
     for (int i = 0; i < qua2.size(); i++) {
          osw.append(qua2.get(i) + "\n");
          }
          osw.flush();
          osw.close();
          } catch (FileNotFoundException e) {
              // TODO Auto-generated catch block
          e.printStackTrace();
     } catch (IOException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
     }
     dem = 0;
Toast.makeText(forth.this, "Dữ liệu đã được xóa",
                                  Toast.LENGTH_SHORT).show();
     }
}
});
Chạy thử, xóa dòng rồi mở lại, dòng bị xóa đã không còn hiện lại nữa.
Bài này chính là cách ứng dụng bài xóa dòng đơn giản trước đây. Trong thực tế ta sẽ làm tương tự thế này chứ không phải xóa rồi mở lại vẫn như cũ.
Sự thực hành này giúp bạn quen với cái gọi là tư duy lập trình, tức cách xử lý các tình huống phát sinh trong thực tế, như ở đây là làm sao để mở lại class thì không có dữ liệu bị ghi lại lần nữa.
Thử xóa toàn bộ các phần tử, thoát ứng dụng, mở lại, bạn sẽ thấy mảng lại đầy đủ như bau đầu.
Đó là vì khi đã xóa hết thì bật ứng dụng lên, file danhsach.txt không có dòng nào thì mảng cũng trắng. Do đó lệnh ghi ở class mở đầu lại ghi vào đầy đủ các dòng.
Do đây là ví dụ, ta không cần quan tâm.
Nhưng nếu buộc để xóa trắng thì mở lại không còn gì nữa, ta sẽ có cách làm thêm một chút.
Kiểu như ở class forth, trước khi thoát về ta kiểm tra số phần tử mảng, nếu bằng 0 là ta biết đã xóa trắng, ta sẽ chuyển ngược về class MainActivity một biến đếm. Mỗi lần mở ứng dụng lại kiểm tra biến đếm, nếu nó bằng số 1 tức đã xóa trắng thì ta không ghi lại nữa.

Đó là cách ta xử lý yêu cầu phát sinh.