안드로이드
Kotlin ListView 구현하기
start1a
2019. 12. 28. 16:11
ListView
- 스크롤할 수 있는 view 항목을 나열한 것
- ListView를 사용하기 위해서는 3가지가 필요함
- 리스트 Model 클래스
- ListView
- 리스트-ListView를 연결할 Adapter 클래스
- 데이터를 관리하고 목록에 표시
구현
- xml에 ListView 생성
- 리스트 Model 클래스 생성
- 각 리스트 멤버를 표시할 xml 레이아웃 디자인
- 각 리스트의 View 객체들을 받을 Adapter Class 생성
- Activity에서 List - Adapter - ListView 연결
1. xml에 ListView 생성
ListView가 필요한 위치에 추가
2. 리스트 Model 클래스 생성
- 리스트의 멤버가 가질 데이터 클래스
- 패키지 우클릭 -> New -> Kotlin File/Class
1
2
|
class People (val name : String, val age : Int)
|
3. 각 리스트 멤버를 표시할 레이아웃 디자인
LinearLayout을 horizontal로 하여 TextView 2개를 나란히 붙였다.

4. 각 리스트의 View 객체들을 받을 Adapter Class 생성
Adapter 클래스를 생성하고 생성자로 ListView를 구현할 Activity의 context와 리스트 데이터로 쓸 객체를 선언한다. BaseAdapter 클래스로부터 상속받아 Adapter의 필수 내부 메서드 4개를 구현한다.
- getView() : 각 리스트의 멤버 View로 보여 줄 객체를 초기화 후 반환
- getItem() : 해당 리스트 position 인덱스의 아이템 반환
- getItemId() : position 인덱스 아이템의 Id를 Long형으로 반환
- getCount() : 리스트에 저장된 아이템의 개수 반환
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
class listAdapter (val context : Context, val list : List<People>) : BaseAdapter() {
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
val view = LayoutInflater.from(context).inflate(R.layout.list_people, null)
val name = view.findViewById<TextView>(R.id.textName)
val age = view.findViewById<TextView>(R.id.textAge)
name.text = list[position].name
age.text = list[position].age.toString()
return view
}
override fun getItem(position: Int): Any {
return list[position]
}
override fun getItemId(position: Int): Long {
return 0
}
override fun getCount(): Int {
return list.count()
}
}
|
getView
- view 객체를 생성
- LayoutInflater가 from() 메서드로 리스트가 표시될 Activity로부터 context를 사용
View로 부풀릴 Layout을 설정 - 데이터를 표시할 name, age TextView를 연결
- TextView 객체로부터 텍스트를 입력
- View 반환
- LayoutInflater가 from() 메서드로 리스트가 표시될 Activity로부터 context를 사용
5. Activity에서 List - Adapter - ListView 연결
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val peopleList = listOf (
People("a", 1),
People("b", 2),
People("c", 3),
People("d", 4),
People("e", 5)
)
val peopleAdapter = listAdapter(this, peopleList)
peopleListView.adapter = peopleAdapter
}
}
|
ViewHolder로 구현하기
- 기존 ListView의 문제점
- ListView의 스크롤을 움직여 보이던 View가 사라지고 다시 보일 때 getView()에서 findViewById를 통해 convertView에 들어갈 View를 다시 찾아야 됨
- 스크롤이 자주 일어나면 View를 찾는 리소스를 많이 사용하게 되어 속도가 떨어짐
- ViewHolder를 통해 한 번 찾은 View를 계속 사용하여 해결함
ViewHolder 클래스 생성
ViewHolder 클래스 생성자에서 두 멤버를 모두 null로 초기화하였다. null을 쓰지 않고 생성자에 직접 View를 넣어도 된다. (holder = viewHolder(view.findViewById(R.id.textName), view.findViewById(R.id.textAge) ))
convertView가 처음 생성될 때는 null이므로 새로운 View 객체와 ViewHolder 객체를 초기화 후 View에 tag로 ViewHolder를 저장한다. tag는 Any라는 최상위 클래스로 어느 타입이든 저장이 가능하다.
나중에 스크롤 발생 이후 다시 호출될 때 convertView는 이미 View가 생성되어 있으므로 View의 tag로 저장했던 ViewHolder 객체를 이용하여 리스트 멤버를 초기화한다.
1
|
private class viewHolder (var name : TextView? = null, var age : TextView? = null)
|
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
|
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View? {
val view : View
val holder : viewHolder
// convertView가 최초로 생성
if (convertView == null)
{
view = LayoutInflater.from(context).inflate(R.layout.list_people, null)
holder = viewHolder()
holder.name = view.findViewById(R.id.textName)
holder.age = view.findViewById(R.id.textAge)
view.tag = holder
}
// 보이지 않던 View가 다시 보여짐
else
{
view = convertView
holder = view.tag as viewHolder
}
val people = list[position]
holder.name?.text = people.name
holder.age?.text = people.age.toString()
return view
}
|