Post

View와 layout Inflate. + ViewHolder // kotlinx

Anko등을 사용하지 않는 일반적인 경우라면 layout은 xml을 이용해서 만들기 때문에, xml layout을 불러와 실제로 앱에 그려주는 작업(View로 만드는 작업)이 필요한데 이를 inflate라고 한다.

1
2
val elementView = inflater.inflate(R.layout.layout\_list\_element, parent, false)

ViewHolder를 사용하고 싶다면, inflate한 View가 가지고 있는 각각의 View 컴포넌트를 멤버로하는 ViewHolder를 만들고 ViewHolder객체를 만든다. findViewById()를 처음 한 번만 호출하고 결과를 ViewHolder에 저장해 놓는 방식으로, 매번 resolve할 필요가 없어 효율적이다. findViewById()를 외부에서 처리하고 ViewHolder로 넘겨도 되고, ViewHolder에서 처리해도 된다. 후자는 view: View만 넘겨 받으면 되니까 깔끔하지만, data class로 만들 수 없다는 단점이 있다. 둘 다 장단이 있으므로 상황에 따라 유연하게 사용하면 될 듯.

1
2
3
4
5
data class ViewHolder(val pic: ImageView,
val name: TextView,
val tel: TextView,
val del: ImageView)

1
2
3
4
5
6
7
8
var holder = ViewHolder(elementView.findViewById(R.id.profile),
elementView.findViewById(R.id.name),
elementView.findViewById(R.id.tel\_num),
elementView.findViewById(R.id.del\_item))
elementView.tag = holder
return elementView
}

findViewById()는 레이아웃이 존재할 때만 View를 리턴하고, 레이아웃이 존재하지 않으면 null을 리턴한다. 해당 view를 어디다 그릴지가 정해져 있지 않은 상태에서 View를 리턴할 수 없기 때문이라고 이해하면 될 것 같다. 그냥 xml대로 그리면 되는거 아닌가 싶지만 이렇게 되면 리스트같은건 요소 수 만큼 view를 xml에 정의해 둘 수도 없는 노릇이니까, 이런 식으로 구현되있는게 아니라 view가 들어가게 될 틀(layout)을 먼저 지정(inflate()setContentView()든) 해야 View를 리턴하게 된다. 특히 kotlinx를 사용할 때 주의해야 한다.

val v = inflate()하는 경우 with (v) { }로 사용할 수 있다.

이 때 View에는 별다른 데이터가 들어있지 않은 상태로, 틀만 잡혀있는 것이기 때문에 ViewHolder에서 View를 꺼내 띄워주면서 데이터를 View에 넣어주어야 하는데 이를 Bind라 한다.

1
2
3
4
5
6
7
8
9
10
override fun bindView(convertView: View, context: Context, cursor: Cursor) {
val holder = convertView.tag as ViewHolder
holder.name.text = String.format("%s (%d)", cursor.getString(1), cursor.getInt(2))
holder.tel.text = cursor.getString(3)
holder.pic.background =
getPicture(cursor.getString(4)) ?:
getDrawable(context.resources, android.R.drawable.ic\_menu\_gallery, null)
holder.del.tag = cursor.getLong(0)
}

This post is licensed under CC BY 4.0 by the author.