Ở bài 15 bạn
đã được thực hành với ListView control. Trong bài tập này bạn sẽ học
cách Custom lại layout cho ListView trong ứng dụng Android của bạn. Tôi
nghĩ bài tập này nó rất quan trọng và thực tế bởi vì trong các ứng dụng
Android có liên quan tới ListView thì đa phần chúng ta phải custom lại
cho đúng với yêu cầu của khách hàng.
Tôi có làm một ví dụ về quản lý nhân viên với giao diện bên dưới đây:

– Bạn quan sát là phần danh sách nhân viên bên dưới là Custom Layout.
– Mỗi dòng trong ListView sẽ có 3 đối tượng: ImageView, TextView và Checkbox.
– Khi nhập nhân viên nếu người sử dụng chọn Nữ thì sẽ hiển thị hình
là con gái, nếu chọn Nam thì hiển thị hình là con trai (bạn nhìn danh
sách hình nhỏ nhỏ 16×16 ở ListView).
– Mã và tên của nhân viên sẽ được hiển thị vào TextView
– Checkbox cho phép người sử dụng checked (nhằm đánh dấu những nhân viên muốn xóa, ở đây cho phép xóa nhiều nhân viên)
– Bạn để ý Tôi có thêm 1 ImageButton có hình màu Chéo đỏ, nó dùng để
xóa tất cả các nhân viên được Checked trong ListView, sau khi xóa thành
công thì phải cập nhật lại ListView.
– Để làm được điều trên thì ta sẽ kế thừa từ ArrayAdapter và override phương thức getView, cụ thể:
– Bạn xem Cấu trúc chương trình quản lý nhân viên:

– Tôi tạo thêm thư mục drawable và kéo thả 3 icon mà Tôi sử dụng vào (bạn cũng tạo thư mục tên y xì vậy). Nhớ là tên hình phải viết liền và chữ thường đầu tiên.
– Trong thư mục layout: Tôi tạo thêm my_item_layout.xml dùng để Custom lại ListView, dưới đây là cấu trúc XML của nó:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
| <? xml version = "1.0" encoding = "utf-8" ?> android:id = "@+id/LinearLayout1" android:layout_width = "match_parent" android:layout_height = "match_parent" android:orientation = "horizontal" > < ImageView android:id = "@+id/imgitem" android:layout_width = "22dip" android:layout_height = "22dip" android:paddingLeft = "2dp" android:paddingRight = "2dp" android:paddingTop = "2dp" android:layout_marginTop = "4dp" android:contentDescription = "here" android:src = "@drawable/ic_launcher" /> < TextView android:id = "@+id/txtitem" android:layout_height = "wrap_content" android:layout_width = "0dip" android:layout_weight = "2" android:layout_marginTop = "4dp" android:paddingLeft = "2dp" android:paddingRight = "2dp" android:paddingTop = "2dp" android:textSize = "15sp" /> < CheckBox android:id = "@+id/chkitem" android:layout_width = "wrap_content" android:layout_height = "wrap_content" /> </ LinearLayout > |
– Ta sẽ dựa vào các id trong này để xử lý trong hàm getView của class mà ta kế thừa từ ArrayAdapter (các id trên là imgitem đại diện cho hình là Nữ hay Nam, txtitem dùng để hiển thị mã và tên nhân viên, chkitem dùng để xử lý Checked)
– Bạn xem activity_main.xml:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
| android:id = "@+id/LinearLayout1" android:layout_width = "match_parent" android:layout_height = "match_parent" android:orientation = "vertical" tools:context = ".MainActivity" > < TextView android:id = "@+id/textView2" android:layout_width = "match_parent" android:layout_height = "wrap_content" android:background = "#008000" android:gravity = "center" android:text = "Quản lý nhân viên" android:textColor = "#FFFFFF" android:textSize = "20sp" /> < TableLayout android:layout_width = "match_parent" android:layout_height = "wrap_content" android:stretchColumns = "*" > < TableRow android:id = "@+id/tableRow1" android:layout_width = "wrap_content" android:layout_height = "wrap_content" > < TextView android:id = "@+id/textView3" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:text = "Mã NV:" /> < EditText android:id = "@+id/editMa" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:ems = "10" > < requestFocus /> </ EditText > </ TableRow > < TableRow android:id = "@+id/tableRow2" android:layout_width = "wrap_content" android:layout_height = "wrap_content" > < TextView android:id = "@+id/textView4" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:text = "Tên NV:" /> < EditText android:id = "@+id/editTen" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:ems = "10" /> </ TableRow > < TableRow android:id = "@+id/tableRow3" android:layout_width = "wrap_content" android:layout_height = "wrap_content" > < TextView android:id = "@+id/textView5" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:text = "Giới tính:" /> < RadioGroup android:id = "@+id/radioGroup1" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:orientation = "horizontal" > < RadioButton android:id = "@+id/radNu" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:checked = "true" android:text = "Nữ" /> < RadioButton android:id = "@+id/radNam" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:text = "Nam" /> </ RadioGroup > </ TableRow > < TableRow android:id = "@+id/tableRow4" android:layout_width = "wrap_content" android:layout_height = "wrap_content" > < Button android:id = "@+id/btnNhap" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:layout_column = "1" android:text = "Nhập NV" /> </ TableRow > </ TableLayout > < LinearLayout android:layout_width = "match_parent" android:layout_height = "wrap_content" > < TextView android:id = "@+id/textView1" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:layout_weight = "9" android:background = "#008000" android:layout_marginTop = "2dp" android:text = "Danh sách nhân viên:" android:textColor = "#FFFFFF" android:textSize = "20sp" /> < ImageButton android:id = "@+id/btndelete" android:layout_width = "30dip" android:layout_height = "30dip" android:src = "@drawable/deleteicon" /> </ LinearLayout > < ListView android:id = "@+id/lvnhanvien" android:layout_width = "match_parent" android:layout_height = "wrap_content" > </ ListView > </ LinearLayout > |
– Layout main này chính là giao diện chính của ứng dụng.
– Dưới đây là các class hỗ trợ xử lý nghiệp vụ:

– Class Employee dùng để lưu trữ thông tin nhân viên: Mã nhân viên, tên nhân viên, giới tính
– Class MyArrayAdapter kế thừa từ ArrayAdapter, mục đích của nó là giúp chúng ta Custom lại layout cho ListView.
– Cuối cùng MainActivity.
– Bây giờ ta vào chi tiết từng class:
1) class Employee:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
| package tranduythanh.com; public class Employee { private String id; private String name; private boolean gender; public String getId() { return id; } public void setId(String id) { this .id = id; } public String getName() { return name; } public void setName(String name) { this .name = name; } public boolean isGender() { return gender; } public void setGender( boolean gender) { this .gender = gender; } @Override public String toString() { return this .id+ "-" + this .name; } } |
2) class MyArrayAdapter:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
| package tranduythanh.com; import java.util.ArrayList; import android.app.Activity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.ImageView; import android.widget.TextView; public class MyArrayAdapter extends ArrayAdapter<Employee> { Activity context= null ; ArrayList<Employee>myArray= null ; int layoutId; /** * Constructor này dùng để khởi tạo các giá trị * từ MainActivity truyền vào * @param context : là Activity từ Main * @param layoutId: Là layout custom do ta tạo (my_item_layout.xml) * @param arr : Danh sách nhân viên truyền từ Main */ public MyArrayAdapter(Activity context, int layoutId, ArrayList<Employee>arr){ super (context, layoutId, arr); this .context=context; this .layoutId=layoutId; this .myArray=arr; } /** * hàm dùng để custom layout, ta phải override lại hàm này * từ MainActivity truyền vào * @param position : là vị trí của phần tử trong danh sách nhân viên * @param convertView: convertView, dùng nó để xử lý Item * @param parent : Danh sách nhân viên truyền từ Main * @return View: trả về chính convertView */ public View getView( int position, View convertView, ViewGroup parent) { /** * bạn chú ý là ở đây Tôi không làm: * if(convertView==null) * { * LayoutInflater inflater= * context.getLayoutInflater(); * convertView=inflater.inflate(layoutId, null); * } * Lý do là ta phải xử lý xóa phần tử Checked, nếu dùng If thì * nó lại checked cho các phần tử khác sau khi xóa vì convertView * lưu lại trạng thái trước đó */ LayoutInflater inflater= context.getLayoutInflater(); convertView=inflater.inflate(layoutId, null ); //chỉ là test thôi, bạn có thể bỏ If đi if (myArray.size()> 0 && position>= 0 ) { //dòng lệnh lấy TextView ra để hiển thị Mã và tên lên final TextView txtdisplay=(TextView) convertView.findViewById(R.id.txtitem); //lấy ra nhân viên thứ position final Employee emp=myArray.get(position); //đưa thông tin lên TextView //emp.toString() sẽ trả về Id và Name txtdisplay.setText(emp.toString()); //lấy ImageView ra để thiết lập hình ảnh cho đúng final ImageView imgitem=(ImageView) convertView.findViewById(R.id.imgitem); //nếu là Nữ thì lấy hình con gái if (emp.isGender()) imgitem.setImageResource(R.drawable.girlicon); else //nếu là Nam thì lấy hình con trai imgitem.setImageResource(R.drawable.boyicon ); } //Vì View là Object là dạng tham chiếu đối tượng, nên //mọi sự thay đổi của các object bên trong convertView //thì nó cũng biết sự thay đổi đó return convertView; //trả về View này, tức là trả luôn //về các thông số mới mà ta vừa thay đổi } } |
– Đây là class quan trọng nhất, mới nhất; dùng để custom layout.
3) class MainActivity:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
| package tranduythanh.com; import java.util.ArrayList; import android.os.Bundle; import android.app.Activity; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.CheckBox; import android.widget.EditText; import android.widget.ImageButton; import android.widget.ListView; import android.widget.RadioGroup; public class MainActivity extends Activity { ArrayList<Employee>arrEmployee= new ArrayList<Employee>(); //Sử dụng MyArrayAdapter thay thì ArrayAdapter MyArrayAdapter adapter= null ; ListView lvNhanvien= null ; Button btnNhap; ImageButton btnRemoveAll; EditText editMa,editTen; RadioGroup genderGroup; @Override protected void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.activity_main); btnNhap=(Button) findViewById(R.id.btnNhap); btnRemoveAll=(ImageButton) findViewById(R.id.btndelete); editMa=(EditText) findViewById(R.id.editMa); editTen=(EditText) findViewById(R.id.editTen); genderGroup=(RadioGroup) findViewById(R.id.radioGroup1); lvNhanvien=(ListView) findViewById(R.id.lvnhanvien); arrEmployee= new ArrayList<Employee>(); //Khởi tạo đối tượng adapter và gán Data source adapter= new MyArrayAdapter( this , R.layout.my_item_layout, // lấy custom layout arrEmployee /*thiết lập data source*/ ); lvNhanvien.setAdapter(adapter); //gán Adapter vào Lisview btnNhap.setOnClickListener( new OnClickListener() { @Override public void onClick(View arg0) { // TODO Auto-generated method stub xulyNhap(); } }); btnRemoveAll.setOnClickListener( new OnClickListener() { @Override public void onClick(View arg0) { xulyXoa(); } }); } //gọi hàm xử lý nhập thông tin nhân viên public void xulyNhap() { String ma=editMa.getText()+ "" ; String ten=editTen.getText()+ "" ; boolean gioitinh= false ; //Nam =false if (genderGroup.getCheckedRadioButtonId()==R.id.radNu) gioitinh= true ; //Tạo một employee Employee emp= new Employee(); emp.setId(ma); emp.setName(ten); emp.setGender(gioitinh); //Đưa vào danh sách arrEmployee.add(emp); //gọi hàm cập nhật giao diện adapter.notifyDataSetChanged(); //Sau khi update thì xóa trắng dữ liệu và cho editma focus editMa.setText( "" ); editTen.setText( "" ); editMa.requestFocus(); } //hàm xử lý xóa public void xulyXoa() { //ta nên đi ngược danh sách, kiểm tra phần tử nào checked //thì xóa đúng vị trí đó ra khỏi arrEmployee for ( int i=lvNhanvien.getChildCount()- 1 ;i>= 0 ;i--) { //lấy ra dòng thứ i trong ListView //Dòng thứ i sẽ có 3 phần tử: ImageView, TextView, Checkbox View v=lvNhanvien.getChildAt(i); //Ta chỉ lấy CheckBox ra kiểm tra CheckBox chk=(CheckBox) v.findViewById(R.id.chkitem); //Nếu nó Checked thì xóa ra khỏi arrEmployee if (chk.isChecked()) { //xóa phần tử thứ i ra khỏi danh sách arrEmployee.remove(i); } } //Sau khi xóa xong thì gọi update giao diện adapter.notifyDataSetChanged(); } } |
– Bây giờ bạn thực hiện chương trình và nhập một số nhân viên, rồi checked rồi nhấn xóa:

– Bạn hãy tìm hiểu thêm trên mạng về cách xử lý các phần tử khi
custom, ở đây Tôi chưa xử lý xong: Ví dụ bạn chưa thể chọn được vào từng
phần tử trong ListView (cho dù bạn có nghiến răng ngoáy mạnh ngón tay
vào thì nó cũng không lung lay, Nếu bạn bỏ CheckBox đi thì lại được)…
Nên bạn tìm hiểu thêm phần xử lý này (how to selected item in custom
ListView).
– Bạn có thể tải toàn bộ coding mẫu ở đây:http://adf.ly/1Yl0PC
– Bạn nên làm tốt bài này vì nó rất quan trọng và hay.
– Trong các bài tập tiếp theo bạn sẽ được thực hành về Spinner,
GridView, kết hợp Spinner với ListView, kết hợp Spinner với GridView.
– Chúc các bạn thành công
No comments:
Post a Comment