티스토리 뷰
커스텀 어댑터?
리스트 뷰를 만들고 그 리스트에 특별한 기능을 추가하고 싶을 때 사용합니다.
Adapter는 BaseAdapter를 상속받습니다.
시작하기
XML
activity_main.xml
// activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
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"
android:orientation="vertical"
tools:context=".MainActivity">
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/TextAppearance.AppCompat.Large"/>
<ListView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
custom_list.xml
// custom_list.xml
<?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:orientation="horizontal">
<TextView
android:id="@+id/list_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/TextAppearance.AppCompat.Large"
android:layout_weight="3"/>
<Button
android:id="@+id/button1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="4"
android:text="1" />
<Button
android:id="@+id/button2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="4"
android:text="2" />
</LinearLayout>
XML은 main xml과 리스트 뷰에 띄어줄 custom_list라는 커스텀 리스트 레이아웃이 있습니다.
리스트 뷰에 데이터 띄어주기
class MainActivity : AppCompatActivity() {
val data = arrayOf("1번째", "2번째", "3번째", "4번째", "5번째", "6번째", "7번째")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val adapter = ArrayAdapter(this, R.layout.custom_list, R.id.list_text, data)
}
}
리스트 뷰에 데이터를 띄어주는 커스텀 리스트 뷰 예제 때 했던 것입니다.
val adapter = ArrayAdapter(this, R.layout.custom_list, R.id.list_text, data)
현재 context를 넣어주고 custom_list를 리스트 뷰의 레이아웃으로 설정하고 data를 적용할 id값과 data를 넣었습니다.
빌드를 하게 되면 아래와 같습니다.
커스텀 어댑터 만들기
이제 리스트 뷰의 커스텀 어댑터를 만들겠습니다.
inner class ListAdapter: BaseAdapter() {
override fun getCount(): Int = data.size
override fun getView(position: Int, view: View?, parent: ViewGroup?): View? {
var convertView: View? = view
if (view == null) {
convertView = layoutInflater.inflate(R.layout.custom_list, null)
}
return convertView
}
override fun getItem(position: Int): Any? = null
override fun getItemId(position: Int): Long = 0
}
커스텀 어댑터의 구조입니다.
-
getCount : Adapter가 관리할 Data의 개수를 설정
-
getView : ListView에 보일 Row를 설정
-
getItem : Adapter가 관리하는 Data의 Item의 Position을 '객체' 형태로 얻음
-
getItemId : Adapter가 관리하는 Data의 Item의 position 값의 id를 얻음
override fun getCount(): Int = data.size
getCount에서는 데이터의 개수를 설정합니다.
override fun getView(position: Int, view: View?, parent: ViewGroup?): View? {
var convertView: View? = view
if (view == null) {
convertView = layoutInflater.inflate(R.layout.custom_list, null)
}
return convertView
}
getView에서는 리스트 뷰에 보일 모양을 설정합니다.
position은 위치, view는 리스트 뷰의 데이터가 사라질 때 반복되게 할 것인지 설정하는 것입니다.
view가 null일 때 converview의 레이아웃을 설정해주고 반환해줍니다.
그리고 image나 button에 Tag를 사용해 position을 붙여줄 수 있습니다.
Tag란 View를 식별할 수 있게 해주는 View의 기능입니다.
override fun getItem(position: Int): Any? = null
getItem에서는 데이터의 위치를 객체 형태로 얻습니다. null을 반환하도록 설정하였습니다.
override fun getItemId(position: Int): Long = 0
getItemId에서는 데이터의 위치 값을 가져옵니다. 0으로 설정하였습니다.
onCreate 부분의 어댑터를 아래와 같이 수정을 합니다.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val adapter = ListAdapter()
listView.adapter = adapter
}
빌드를 하게 되면 아래와 같이 나오게 됩니다.
데이터의 값이 나오지 않은 이유는 어댑터의 getView에서 TextView에 데이터를 넣지 않아서 그렇습니다.
리스트 뷰에 데이터 나오게 설정하기
override fun getView(position: Int, view: View?, parent: ViewGroup?): View? {
...
val text: TextView? = convertView?.findViewById(R.id.list_text)
text?.text = data[position]
return convertView
}
위와 같이 설정을 해주고 빌드를 하게 되면 아래와 같이 리스트 뷰에 데이터가 출력되게 됩니다.
어댑터 사용해서 리스트 뷰 버튼 클릭 이벤트 구현하기
inner class ButtonClickListener: View.OnClickListener {
override fun onClick(v: View?) {
when(v?.id) {
R.id.button1 -> textView.text = "1번 버튼 클릭"
R.id.button2 -> textView.text = "2번 버튼 클릭"
}
}
}
ButtonClickListener라는 inner 클래스를 만들고 View.OnClickListener를 상속받아 각 버튼이 눌리면 textView의 text를 바꿔주는 코드를 구현하였습니다.
override fun getView(position: Int, view: View?, parent: ViewGroup?): View? {
...
val button1: Button? = convertView?.findViewById(R.id.button1)
val button2: Button? = convertView?.findViewById(R.id.button2)
button1?.setOnClickListener(ButtonClickListener())
button2?.setOnClickListener(ButtonClickListener())
...
return convertView
}
getView에 위의 코드를 추가하였습니다. converView에서 버튼의 id를 가져와 setOnClickListener를 설정한 코드입니다.
빌드를 하게 되면 아래와 같이 버튼 이벤트가 동작하는 것을 확인할 수 있습니다.
버튼 클릭 시 리스트 뷰의 위치 값을 가져와서 보여주기
마지막으로 버튼 클릭 시에 리스트 뷰에 클릭된 데이터의 순서를 가져오는 것을 구현할 것입니다.
override fun getView(position: Int, view: View?, parent: ViewGroup?): View? {
...
button1?.tag = position
button2?.tag = position
...
return convertView
}
getView에서 button에 tag를 사용하여 위치를 등록시킵니다.
inner class ButtonClickListener: View.OnClickListener {
override fun onClick(v: View?) {
val position = v?.tag as Int + 1
when(v.id) {
R.id.button1 -> textView.text = "${position}번째에 있는 1번 버튼 클릭"
R.id.button2 -> textView.text = "${position}번째에 있는 2번 버튼 클릭"
}
}
}
ButtonClickListener의 코드를 위와 같이 수정합니다.
position은 View의 tag를 Integer 형으로 가져오고 1을 더해줍니다. ( 리스트 뷰의 순서는 0번부터 시작 )
빌드를 하게 되면 아래와 같은 결과가 나오는 것을 확인할 수 있습니다.
예제 코드
https://github.com/Im-Tae/Blog_Example/tree/master/Android/CustomAdapterExample
'알려주는 이야기 > 안드로이드' 카테고리의 다른 글
안드로이드 스튜디오 에뮬레이터에서 localhost 접속 (0) | 2020.07.08 |
---|---|
안드로이드 다이얼로그 예제 (0) | 2020.07.02 |
안드로이드 Lottie 라이브러리 (0) | 2020.07.01 |
안드로이드 뷰 페이저 (0) | 2020.07.01 |
안드로이드 커스텀 리스트 뷰 (0) | 2020.06.30 |