Uknow's Lab.
article thumbnail

리스트뷰와 리사이클러뷰의 아이템 클릭 리스너

 

 

ListView에 아이템 클릭 이벤트 리스너를 넣는 것은 꽤 간단했습니다.

그냥 버튼 클릭 리스너를 다는것과 같이 setOnItemClickListener를 달아주면 되니까요

하지만 RecyclerView 안에는 어떠한 itemClickListener를 찾아볼 수 없었습니다.

 

이는 아이템뷰를 재사용(Recylce)하는 리사이클러뷰의 특성 때문입니다.

뷰를 재사용하기 때문에, 리스트뷰보다 적은 리소스를 사용하며, 더 유연하고 자유롭지만,

마찬가지로 뷰를 재사용하기 때문에, 아이템을 클릭했을 때 이벤트를 처리하기가 어렵다고 하네요.

 

하지만, 방법이 없는것은 아닙니다. 저희가 직접 아이템 클릭 리스너를 구현하여 넣어주면 되니까요.

 

참고로 본 포스팅에서 사용하는 리사이클러뷰 예제는 기존 포스팅에서 썼던 리사이클러뷰를 바탕으로 작성되었습니다.

https://uknowblog.tistory.com/29

 

[안드로이드/코틀린] 리사이클러뷰(RecyclerView) 사용법 및 예제

리사이클러뷰(RecyclerView) 리사이클러뷰는 안드로이드에서 리스트를 만들기 위해 사용되는 뷰 입니다. 리스트를 만들기 위해 사용된다는 점에서 리스트뷰(ListView)와 비슷하지만, 뷰를 재활용(Recyc

uknowblog.tistory.com

 

 

 

리사이클러뷰 아이템 클릭 리스너 구현하기

inner class BoardViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
    val tv_time = itemView.findViewById<TextView>(R.id.tv_time)
    val tv_title = itemView.findViewById<TextView>(R.id.tv_title)
    val tv_name = itemView.findViewById<TextView>(R.id.tv_name)

    init {
        itemView.setOnClickListener {

        }
    }
}

사실 아이템 클릭 리스너는 그냥 ViewHolder안에서

itemView에 클릭 리스너를 넣어주면 됩니다. 참 쉽죠?

해당 아이템의 위치를 얻기 위해서는 adapterPosition 메소드를 호출하여 알 수 있습니다

 

하지만... 이것도 좋기는 한데 아무래도 Activity에서 setOnItemClickListener를 해주는 쪽이 더 편하겠지요?

 

리사이클러뷰 외부에서 ItemClickListener 달기

ViewHolder와 Adapter에서 인터페이스 정의

interface OnItemClickListener {
    fun onItemClick(position: Int) {}
}

var itemClickListener: OnItemClickListener? = null

BoardAdapter.kt

 

먼저, OnItemClickListener 인터페이스와 onItemClick 메소드를 만들어주고,

위에서 만든 OnItemClickListener를 인스턴스화 시킵니다.

 

inner class BoardViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
    val tv_time = itemView.findViewById<TextView>(R.id.tv_time)
    val tv_title = itemView.findViewById<TextView>(R.id.tv_title)
    val tv_name = itemView.findViewById<TextView>(R.id.tv_name)

    init {
        itemView.setOnClickListener {
            itemClickListener?.onItemClick(adapterPosition)
        }
    }
}

그리고 ViewHolder에서 itemClickListener의 onItemClick 메소드를 호출해줍니다.

그리고 클릭한 아이템이 몇 번째 아이템인지를 반환하는 adapterPosition 메소드를 호출해,

아이템의 position를 매개 변수로 넘겨줍니다.

 

 

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView

class BoardAdapter(val itemList: ArrayList<BoardItem>) :
    RecyclerView.Adapter<BoardAdapter.BoardViewHolder>() {

    interface OnItemClickListener {
        fun onItemClick(position: Int) {}
    }

    var itemClickListener: OnItemClickListener? = null

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BoardViewHolder {
        val view =
            LayoutInflater.from(parent.context).inflate(R.layout.item_recycler_view, parent, false)
        return BoardViewHolder(view)
    }

    override fun onBindViewHolder(holder: BoardViewHolder, position: Int) {
        holder.tv_time.text = itemList[position].time
        holder.tv_title.text = itemList[position].title
        holder.tv_name.text = itemList[position].name
    }

    override fun getItemCount(): Int {
        return itemList.count()
    }


    inner class BoardViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val tv_time = itemView.findViewById<TextView>(R.id.tv_time)
        val tv_title = itemView.findViewById<TextView>(R.id.tv_title)
        val tv_name = itemView.findViewById<TextView>(R.id.tv_name)

        init {
            itemView.setOnClickListener {
                itemClickListener?.onItemClick(adapterPosition)
            }
        }
    }
}

BoardAdapter.kt의 전체 코드 입니다.

 

액티비티에서 리사이클러뷰에 onItemClickListener set 해주기

val boardAdapter = BoardAdapter(itemList)
boardAdapter.notifyDataSetChanged()

rv_board.adapter = boardAdapter
rv_board.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)

boardAdapter.itemClickListener = object : BoardAdapter.OnItemClickListener {
    override fun onItemClick(position: Int) {
        val item = itemList[position]
        Toast.makeText(applicationContext, "${item.title} 클릭함", Toast.LENGTH_SHORT).show()
    }
}

버튼에 onClickListener를 달아주듯이, boardAdapter에 위에서 정의한 onItemClickListener를 달아줍니다.

위 예제는 매개변수인 position을 사용해 내가 클릭한 아이템의 제목을 출력하는 코드입니다.

 

 

보다시피 클릭한 글의 제목을 가져온 모습이네요.

 

RecyclerView는 ListView처럼 기본적으로 itemClickListener를 제공하진 않지만,

직접 itemClickListener를 구현하여 아이템을 클릭했을 때 이벤트를 처리할 수 있었습니다.

 

 

 

해당 리스너 구현 원리와 디자인 패턴에 관해 더 알고 싶으신 분은

 

Strategy 패턴과 Strategy 패턴의 파생 패턴인 Template Callback Pattern,

https://uknowblog.tistory.com/343

 

[디자인 패턴] Strategy(전략) 패턴 + Template Callback Pattern

Strategy Pattern 스트레티지, 혹은 전략 패턴은 코드가 실행되는 중인 런타임 환경 중, 객체를 바꾸는 패턴입니다. 일반적으로 상속을 사용할 경우, 코드 작성 단계에서 이미 부모 클래스를 상속받

uknowblog.tistory.com

 

 

Observer 패턴에 관한 글을 참고해주세요.

https://uknowblog.tistory.com/389

 

[디자인 패턴] Observer(옵저버) 패턴

Observer Pattern (옵저버 패턴) 옵저버 패턴은 특정 객체를 관찰(Observe)하다가, 해당 객체의 상태가 변경된다면 이를 관측하고 있는 객체들에게 연락을 하는 일대다(one-to-many) 의존성을 정의합니다.

uknowblog.tistory.com

 

profile

Uknow's Lab.

@유노 Uknow

인생은 Byte와 Double 사이 Char다. 아무말이나 해봤습니다.