[Kotlin] RecyclerView

이상목·2024년 5월 24일
0

Kotlin

목록 보기
11/20

오늘은 listview와 비슷한 RecylcerView를 알아보는 시간을 갖도록 하겠습니다.


RecyclerView란 ?

  • RecyclerView는 안드로이드 앱에서 리스트 형태의 데이터를 표시하는데 사용되는 위젯입니다.
  • 여러 아이템을 스크롤 가능한 리스트로 표현하며, 많은 아이템을 효율적으로 관리하고 보여주는 역할을 합니다.
  • 뷰 바인딩을 사용하여 XML 레이아웃 파일과 액티비티를 연결합니다
Recyle → 재활용하다.
View를 재활용하여 사용하는 방법

ListView와 RecyclerView의 차이점
- ListView
스크롤 할 때마다 위에 있던 아이템은 삭제되고, 
맨 아래 아이템은 생성 되길 반복합니다.
아이템 개수 만큼 삭제와 생성을 반복하여 성능에 좋지 않습니다.
- RecyclerView
스크롤 할 때마다 위에 있던 아이템이 재활용 되어 아래로 이동하여 재사용 됩니다.
예를 들어 10개 정도 View를 만들고 10개를 재활용하여 사용합니다.
View를 계속 만드는 ListView의 단점을 보완할 수 있습니다.

RecyclerView의 기본 구조

  • Adapter
데이터를 목록 형태로 보여주기 위해 사용됩니다.
데이터를 아이템 뷰와 연결하는 역할을 합니다.
데이터와 RecyclerView 사이의 통신을 위한 연결체 입니다.
  • ViewHolder
아이템 뷰를 보유(저장)하고 표시하는 역할을 합니다.
스크롤 해서 위로 올라간 View를 재활용하기 위해 View를 기억하는 역할을 합니다.
  • LayoutManager
데이터나 아이템들이 리사이클러뷰 내부에서 배치되는 형태(방식)을 관리합니다.
종류
LinearLayoutManager : 수평, 수직으로 배치 시켜줍니다.
GridLayoutManager : 그리드 화면으로 배치 시켜줍니다.
StaggeredGridLayoutManager : 높이가 불규칙한 그리드 화면으로 배치 시켜줍니다.


실습

1. activity_main 레이아웃 구성

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:id="@+id/main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rv"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
  • RecyclerView 태그 생성 후 ID를 지정해준다.

2. rv_item 레이아웃 구성

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/rv_item"
        android:text="rv"
        android:textSize="20sp"
        android:layout_margin="20dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        tools:ignore="MissingConstraints"/>

</androidx.constraintlayout.widget.ConstraintLayout>
  • item 목록에 보여질 text를 정의하기 위해 TextView 목록을 생성하였습니다.

3. MainActivity 구성 - 아이템 생성

package com.sangmoki.rv_practice

import android.os.Bundle
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        setContentView(R.layout.activity_main)

        // RecyclerView에 들어갈 아이템 리스트 생성
        val items = mutableListOf<String>()

        // 아이템 리스트에 아이템 추가
        items.add("1")
        items.add("2")
        items.add("3")

        // RecyclerView에 Adapter 연결
        val rv = findViewById<RecyclerView>(R.id.rv)
        val rvAdapter = RvAdapter(items)

        // RecyclerView에 Adapter 설정
        rv.adapter = rvAdapter
        // RecyclerView의 레이아웃 매니저 설정
        rv.layoutManager = LinearLayoutManager(this)
    }
}
  • RecylerView에 들어갈 String 타입의 아이템 목록을 생성하고, 아이템을 생성해주었습니다.
  • 이후, RecyclerView에 Adapter를 연결하여 주었습니다.

4. Adapter 생성

package com.sangmoki.rv_practice

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

class RvAdapter(val items: MutableList<String>) : RecyclerView.Adapter<RvAdapter.ViewHolder>() {

    var itemClick : ItemClick ? = null

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RvAdapter.ViewHolder {
        // 뷰홀더를 생성하고 뷰를 붙여주는 부분
        var view = LayoutInflater.from(parent.context).inflate(R.layout.rv_item, parent, false)
        // 생성한 뷰를 ViewHolder에 넣어 반환
        return ViewHolder(view)
    }

    override fun onBindViewHolder(holder: RvAdapter.ViewHolder, position: Int) {
        // items 리스트에서 position에 해당하는 데이터를 가져온다.
        val item = items[position]
        
        // itemClick이 되었을 때 실행 조건
        if (itemClick != null) {

            // 클릭 이벤트 구현
            holder.itemView.setOnClickListener { v ->
                itemClick?.onClick(v, position)
            }
        }

        // bindItem 메소드를 호출하여 데이터를 뷰에 바인딩한다.
        holder.bindItem(item)

    }

    override fun getItemCount(): Int {
        // items 리스트의 크기를 반환한다.
        return items.size
    }

    inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {

        // 뷰홀더에 각각의 아이템을 바인딩하는 역할을 하는 메소드
        fun bindItem(item: String) {
            // rv_item layout의 id를 가져와 text를 item으로 치환해준다.
            val rv_text = itemView.findViewById<TextView>(R.id.rv_item)
            rv_text.text = item
        }
    }

    // 클릭 이벤트를 위한 인터페이스 정의
    interface ItemClick {
        fun onClick(view: View, position: Int)
    }

}
  • listView와 비슷하지만, implements 되는 메서드가 다름으로 onCreateViewHolder에서 inflator를 통해 뷰 홀더를 생성하여 반환해주고,
  • onBindViewHolder를 통해 MainActivity에서 정의한 items 목록을 가져와 holder.bindItem을 통해 데이터 뷰(rv_item layout)에 바인딩합니다.

4-1. 클릭 이벤트 생성

 var itemClick : ItemClick ? = null
 
 // 클릭 이벤트를 위한 인터페이스 정의
 interface ItemClick {
     fun onClick(view: View, position: Int)
 }
 
 override fun onBindViewHolder(holder: RvAdapter.ViewHolder, position: Int) {
        // items 리스트에서 position에 해당하는 데이터를 가져온다.
        val item = items[position]
        
        // itemClick이 되었을 때 실행 조건
        if (itemClick != null) {

            // 클릭 이벤트 구현
            holder.itemView.setOnClickListener { v ->
                itemClick?.onClick(v, position)
            }
        }

        // bindItem 메소드를 호출하여 데이터를 뷰에 바인딩한다.
        holder.bindItem(item)
    }
  • ListView와 다르게 onClick 이벤트를 각각의 이벤트에 부여하는 방법이 조금 까다롭다.
  • 클릭되었는지 확인하는 플래그 변수와 클릭 이벤트를 위한 인터페이스를 정의하고, onBindViewHolder에서 클릭 이벤트를 구현합니다.



오늘은 RecyclerView에 대해 알아보았는데, ListView와의 비교를 정리해보자면, RecylcerView는 직접 클릭이벤트를 작성해주어야 하는 번거로움이 있지만, ViewHolder를 통하여 재사용할 수 있는 장점이 있어 ListView보다 성능이 좋다는 장점을 가지고 있습니다.

profile
기록은 기억을 지배한다.

0개의 댓글