본문 바로가기
Android

[Android] RecyclerView 이해하기 (2) - RecyclerViewAdapter 내부요소를 외부에서 사용하는 방법

by Glion 2023. 5. 24.
반응형

지난번 포스팅에서 리사이클러뷰에 대해 정리하고 아이템을 넣어보았다.

이번 포스팅에서는 interface를 사용하여 Adapter에 있는 pos와 같은 값을 MainActivity에서 사용할 수 있게끔 해 볼 것이다.

 

우선, 리사이클러뷰의 각 요소에 대해 다시 정리해보자.

 

  • ViewHolder
    생성된 ViewHolder는 아이템의 모양을 보관하고 있고, 여기에 데이터만 변경하여 사용하게 된다.
  • onCreateViewHolder
    미리 정의한 리사이클러뷰의 한 아이템의 xml 레이아웃을 inflate하여 view의 형태로 ViewHolder 객체를 생성해준다
  • getItemCount
     Adapter가 생성되면 제일 먼저 실행되는 함수로, 리스트로 생성해야 하는 아이템들의 총 개수를 반환한다.
  • onBindViewHolder
    생성될 아이템의 position을 바탕으로 데이터를 ViewHolder가 기억하고 있는 아이템에 Bind해준다.

지난번에 작성했던 아이템의 레이아웃은 다음과 같았다.

여기서 "항목은 ~~ 입니다" 부분을 클릭했을때 이벤트를 주고 싶다면, setOnClickListener 이벤트를 이용하여 만들 수 있을 것이다.

 

그러나, RecyclerViewAdapter 내부가 아닌, 외부에서 클릭이벤트를 처리하고 싶다면? 혹은 외부에서 RecyclerViewAdapter의 요소를 사용하고 싶다면 어떻게 해야 할까?

 

우선 아래와 같이 RecyclerViewAdapter 내부에 인터페이스를 생성한다.리사이클러뷰의 요소인 아이템의 position을 외부에서 사용하기 위해 다음과 같이 onClick의 매개변수로 position을 넣어주었다.

    interface OnItemClickListener{
        fun onClick(position: Int)
    }

또한, 외부에서 이벤트를 처리하기 위해 RecyclerViewAdapter 의 매개변수에 인터페이스 타입으로 리스너를 추가해준다.
다음과 같은 형태가 될 것이다.

class BottomRecyclerViewAdapter(private val itemList: ArrayList<ExampleList>, private val mContext: Context, private val listener: OnItemClickListener) : RecyclerView.Adapter<BottomRecyclerViewAdapter.ViewHolder>()

이제 원하는곳에서 listener.onClick을 호출해주면 된다. 

"항목은 ~~ 입니다" 부분을 클릭했을때 이벤트를 주어 외부에서 처리하도록 한다.

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val item = itemList[position]
        holder.title.text = mContext.getString(R.string.temp_title, item.number)
        holder.content.text = mContext.getString(R.string.temp_content, item.number)

        holder.content.setOnClickListener {
            listener.onClick(position)
        }
    }

onBindViewHolder 는 화면에 나타낼 아이템의 position에 따라 데이터를 Bind해준다. 여기에 setOnClickListener를 달아 아이템마다 클릭이벤트를 달아주고, OnItemClickListener 타입의 listener의 onClick함수를 호출해준다.

인자로 position을 넘겨 외부에서 position 값을 사용할 수 있다.

 

이제 RecyclerViewAdapter 외부로 나와 리사이클러뷰 어댑터 붙이는 부분에 객체표현식으로 listener를 달아준다.

 

*MainActivity

        mRecyclerViewBottom.adapter = BottomRecyclerViewAdapter(mBottomItemList, this, object: BottomRecyclerViewAdapter.OnItemClickListener{
            override fun onClick(position: Int) {
                // 리사이클러뷰에서 아이템의 포지션을 사용할 수 있음. 지금은 content.setOnClickListener에 달아서 position을 넘겨주기 때문에 클릭한 위치의 포지션이 넘어옴
                Toast.makeText(mContext, "선택한 항목의 포지션 : $position", Toast.LENGTH_SHORT).show()
            }
        })

object: BottomRecyclerViewAdapter.OnItemClickListener가 그 부분이다. 인터페이스를 구현하였기에 onClick 함수를 오버라이딩 해주어 내용을 작성한다.

매개변수로 리사이클러뷰의 position이 넘어오기 때문에 외부에서 position 값에 대한 사용이 가능하다.

 

클릭 이벤트 처리는 다음의 순서로 외부로 넘어가게 된다.

먼저 아이템을 클릭하면 정의한 RecyclerViewAdapter 내부의 onBindViewHolder 의 setOnClickListener가 호출된다.

이후 listener에게 onClick함수를 실행하라고 하고,  MainActivity의 오버라이드된 onClick 메소드가 실행된다.

 

전체코드는 다음과 같다.

 

* RecyclerViewAdapter.kt

class BottomRecyclerViewAdapter(private val itemList: ArrayList<ExampleList>, private val mContext: Context, private val listener: OnItemClickListener) : RecyclerView.Adapter<BottomRecyclerViewAdapter.ViewHolder>() {
    interface OnItemClickListener{
        fun onClick(position: Int)
    }

    class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView){
        private var mBinding : ItemTempRecyclerBinding? = null
        init{
            mBinding = ItemTempRecyclerBinding.bind(itemView)
        }
        val title = mBinding!!.tvTitle
        val content = mBinding!!.tvContent
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val itemView = LayoutInflater.from(mContext).inflate(R.layout.item_temp_recycler, parent, false)
        return ViewHolder(itemView)
    }

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

    override fun getItemId(position: Int): Long {
        return position.toLong()
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val item = itemList[position]
        holder.title.text = mContext.getString(R.string.temp_title, item.number)
        holder.content.text = mContext.getString(R.string.temp_content, item.number)

        holder.content.setOnClickListener {
            listener.onClick(position)
        }
    }
}

* MainActivity

class RecyclerViewActivity : AppCompatActivity() {
    private lateinit var mRecyclerViewTop: RecyclerView
    private lateinit var mRecyclerViewBottom: RecyclerView
    private lateinit var mTopItemList: ArrayList<ExampleList>
    private lateinit var mBottomItemList: ArrayList<ExampleList>
    private lateinit var mContext: Context

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_recycler_view)
        mContext = this
        mRecyclerViewBottom = findViewById(R.id.rv_temp2)

        // 아이템에 들어갈 리스트 준비
        mBottomItemList = ArrayList()
        for(i: Int in 1..100){
            mBottomItemList.add(ExampleList(i,false))
        }
        mRecyclerViewBottom.setHasFixedSize(true)
        mRecyclerViewBottom.layoutManager = LinearLayoutManager(this, RecyclerView.VERTICAL, false)
        mRecyclerViewBottom.adapter = BottomRecyclerViewAdapter(mBottomItemList, this, object: BottomRecyclerViewAdapter.OnItemClickListener{
            override fun onClick(position: Int) {
                // 리사이클러뷰에서 아이템의 포지션을 사용할 수 있음. 지금은 content.setOnClickListener에 달아서 position을 넘겨주기 때문에 클릭한 위치의 포지션이 넘어옴
                Toast.makeText(mContext, "선택한 항목의 포지션 : $position", Toast.LENGTH_SHORT).show()
            }
        })
    }
}

 

다음 글에서는 이렇게 세팅한 RecyclerView의 항목을 클릭했을때 색상이 변하게 하고, 한개의 항목만 색상이 변하도록 다른 항목을 클릭하면 기존의 항목은 해제되도록 해보겠다.

반응형