티스토리 뷰

반응형

커스텀 어댑터?

 

리스트 뷰를 만들고 그 리스트에 특별한 기능을 추가하고 싶을 때 사용합니다.

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

반응형
댓글