Diary of Duc

Android - Custom Listview

2018-08-28

Default ListView

ListView mặc định sẽ trông thế này, mỗi dòng 1 TextView.

Code ra nó chỉ cần dùng default Adapter như này:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class MainActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setUI()
}

fun setUI(){
val listView = ListView(this)
rl_main_activiy.addView(listView) /* rl_main_activiy: root view id */
val data = arrayListOf("a", "b", "c", "d", "e", "f", "g", "h", "i", "k", "l", "m")
listView.adapter = ArrayAdapter( this, android.R.layout.simple_list_item_1, data)
}

}

Nếu vẫn chưa biết Adapter để làm gì, thì nó đóng vai trò như lớp trung gian để đổ dữ liệu vào ListView (nói riêng).

Mà còn thắc mắc findViewById() ở đâu thì xin nhắc đây là Kotlin nhé, không phải Java.

Giờ muốn hiện thị nhiều hơn thì sao? Như là hiện thị 3 TextView trên 1 dòng. Câu trả lời là hãy đi custom ListView.

Custom Listview

Custom Layout

Tạo 1 custom Layout như thế này:

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
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingBottom="10dp"
android:paddingTop="10dp">

<TextView
android:id="@+id/textView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="30"
android:layout_marginLeft="10dp"
android:gravity="left"
android:text="a"/>

<TextView
android:id="@+id/textView2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="30"
android:gravity="center"
android:text="b"/>

<TextView
android:id="@+id/textView3"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="30"
android:layout_marginRight="10dp"
android:gravity="right"
android:text="c"/>

</LinearLayout>

</android.support.constraint.ConstraintLayout>

Trông sẽ như thế này:

Custom Adapter

Data là class chứa 3 giá trị của 3 TextView:

1
class Data(val p1: String, val p2: String, val p3: String)

Tạo 1 class ListviewAdapter, class này extend lại BaseAdapter Hoặc ArrayAdapter, ở đây sẽ extend BaseAdapter.

Sau đó ta cần override nhưng phương thức của lớp Cha:
* getView(): Trả về view cho mỗi item trong ListView
* getItem(): Trả về vị trí của item trong ListView
* getItemId(): Trả về id của item trong ListView
* getCount(): Trả về kích cỡ của ListView

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
class ListviewAdapter(val activity: MainActivity, val data: ArrayList<Data>): BaseAdapter(){

override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
val inflater = activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
val layout = inflater.inflate(R.layout.custom_layout, null)
layout.textView.text = data[position].p1
layout.textView2.text = data[position].p2
layout.textView3.text = data[position].p3
return layout
}

override fun getItem(position: Int): Any {
Log.d("getItem", position.toString())
return position
}

override fun getItemId(position: Int): Long {
Log.d("getItemId", position.toString())
return position.toLong()
}

override fun getCount(): Int {
return data.size
}

}

Chắc là ai cũng thắc mắc là getItem() với getItemId() để làm gì.

Trong getView(), ngoài cách lấy vị trí item trực tiếp từ biến postion, ta có còn có 1 cách nữa, đó là lấy thông qua getItem() hoặc getItemId().

Khác nhau là khi lấy vị trí trực tiếp từ biến postion, thì chỉ có thể lấy thôi. Nhưng lấy qua getItem() hoặc getItemId(), ta còn có thể làm nhiều thứ nữa, như đoạn code bên trên sẽ show Log() ra chẳng hạn.

getItem()getItemId() cũng không khác nhau ngoài trả về khác kiểu dữ liệu, nếu item có id riêng thì sẽ thực hiện lấy id đó trong getItemId().

Set Adapter

Có custom Layout và custom Adapter rồi, việc cuối cùng là đổ dữ liệu vào ListView thông qua custom Adapter

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
class MainActivity : AppCompatActivity() {

private val data = ArrayList<Data>()
private lateinit var listView: ListView
private lateinit var listViewAdapter: ListviewAdapter

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setUI()
}

fun setUI(){
listView = ListView(this)
rl_main_activiy.addView(listView)
data.add(Data("a","b","c"))
data.add(Data("d","e","f"))
data.add(Data("g","h","i"))
data.add(Data("k","l","m"))
data.add(Data("n","o","p"))
data.add(Data("q","r","s"))
data.add(Data("a","b","c"))
data.add(Data("d","e","f"))
data.add(Data("g","h","i"))
data.add(Data("k","l","m"))
data.add(Data("n","o","p"))
data.add(Data("q","r","s"))
data.add(Data("a","b","c"))
data.add(Data("d","e","f"))
data.add(Data("g","h","i"))
data.add(Data("k","l","m"))
data.add(Data("n","o","p"))
data.add(Data("q","r","s"))
listViewAdapter = ListviewAdapter(this, data)
listView.adapter = listViewAdapter
}

}

Kết quả:

Events

Sau khi đã custom ListView, chúng ta cần bắt sự kiện cho nó:

* parent: view cha.
* view: view đã chạm.
* position: vị trí trong ListView.
* id: id của view.

OnItem

Sự kiện khi chạm

1
2
3
listView.setOnItemClickListener { parent, view, position, id ->
Toast.makeText(this, "One ${view.textView.text} ${view.textView2.text} ${view.textView3.text}", Toast.LENGTH_SHORT).show()
}

OnItemLong

Sự kiện khi chạm và giữ

1
2
3
4
listView.setOnItemLongClickListener { parent, view, position, id ->
Toast.makeText(this, "Long ${view.textView.text} ${view.textView2.text} ${view.textView3.text}", Toast.LENGTH_SHORT).show()
true
}

Add, Remove Items

Add Items

Thêm một phần tử vào ListView:

1
2
data.add(Data("new item","new item","new item"))
listViewAdapter.notifyDataSetChanged()
Remove Items

Xóa phẩn tử khỏi ListView:

1
2
data.removeAt(position)
listViewAdapter.notifyDataSetChanged()

Phải chắc chắn gọi notifyDataSetChanged() để thay đổi.

Tags: android

URL QR