Uknow's Lab.
article thumbnail

리사이클러뷰(RecyclerView)

리사이클러뷰는 안드로이드에서 리스트를 만들기 위해 사용되는 뷰 입니다.

 

리스트를 만들기 위해 사용된다는 점에서 리스트뷰(ListView)와 비슷하지만,

뷰를 재활용(Recycler)한다는 점에서 리스트뷰보다 더 개선된 형태입니다.

 

하지만, 뷰를 재활용 하기 때문에 각 뷰의 내용을 담아둘 뷰 홀더(View Holder)가 필요합니다.

 

 

 

아이템 레이아웃 만들기

<?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="wrap_content"
    android:orientation="horizontal"
    android:paddingHorizontal="15dp"
    android:paddingVertical="20dp">

    <TextView
        android:id="@+id/tv_time"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="13:42" />

    <TextView
        android:id="@+id/tv_title"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:paddingHorizontal="10dp"
        android:text="글 제목" />

    <TextView
        android:id="@+id/tv_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="홍길동" />
</LinearLayout>

item_recycler_view.xml

아이템의 각 행을 담을 레이아웃을 만듭니다.

 

 

데이터 클래스 만들기

data class BoardItem(val time: String, val title: String, val name: String)

 

리스트의 각 아이템의 내용이 담길 데이터 클래스를 하나 만듭니다.

저는 예시로 글 작성 시간, 글 제목, 글 작성자를 담은 데이터클래스를 생성하였습니다.

 

 

리사이클러뷰 어댑터 만들기

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

    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)
    }
}

 

어댑터 클래스는 RecyclerView.Adapter<ViewHolder>를 상속받고,

onCreateViewHolder, onBindViewHolder, getItemCount를 각각 오버라이딩 해줍니다.

 

 

 

ViewHolder

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)
}

ViewHolder는 어댑터 클래서 외부 혹은 내부에 RecyclerView.ViewHolder클래스를 상속하여 만듭니다.

각 뷰들을 itemView.findViewById를 사용하여 해당 뷰를 연결합니다.

 

 

 

onCreateViewHolder

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)
}

 

onCreateViewHolder 메소드는 뷰가 만들어질때(create) 호출되는 메소드입니다.

 

위에서 만든 각 행 레이아웃(R.layout.item_recycler_view)를 인플레이트하여 뷰 홀더를 생성해 return 해줍니다.

 

 

 

onBindViewHolder

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
}

onBindViewHolder는 뷰가 바인드(Bind)될때 호출되는 메소드입니다.

 

onCreateViewHolder에서 뷰가 만들어졌다면, onBindViewHolder는 뷰에 내용이 씌워질때라 보시면 될 것 같습니다.

 

리사이클러뷰가 한번 만들어지면, 각 뷰는 한번만 create되지만, 삭제되지 않고 계속 재활용(recycle)되기 때문에,

 

onCreateViewHolder는 리사이클러뷰가 만들어질때만 호출되나,

 

onBindViewHolder는 스크롤을 내리거나 올릴때마다 호출됩니다.

 

 

getItemCount

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

getItemCount는 리스트의 수를 return 합니다.

 

 

 

xml에 리사이클러뷰 넣기

<?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:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rv_board"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:listitem="@layout/item_recycler_view" />

</androidx.constraintlayout.widget.ConstraintLayout>

 

 

리사이클러뷰 속성에

tools:listitem="@layout/item_recycler_view"

를 추가하면 해당 아이템으로 리사이클러뷰를 볼 수 있습니다.

 

tools 속성은 xml에서만 보일 뿐, 실제 앱 동작 상에선 영향을 끼치지 않습니다.

 

 

리사이클러뷰에 어댑터 붙이기

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

        val rv_board = findViewById<RecyclerView>(R.id.rv_board)


        val itemList = ArrayList<BoardItem>()

        itemList.add(BoardItem("13:00","월급 두배로 받는법","김XX"))
        itemList.add(BoardItem("11:00","학점 A+ 받는 법","이XX"))
        itemList.add(BoardItem("10:00","구글 면접 질문에 대답하는 법","박XX"))
        itemList.add(BoardItem("08:00","공부 잘하는 MBTI 순위","최XX"))

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

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

 

 

 

 

 

val itemList = ArrayList<BoardItem>()

itemList.add(BoardItem("13:00","월급 두배로 받는법","김XX"))
itemList.add(BoardItem("11:00","학점 A+ 받는 법","이XX"))
itemList.add(BoardItem("10:00","구글 면접 질문에 대답하는 법","박XX"))
itemList.add(BoardItem("08:00","공부 잘하는 MBTI 순위","최XX"))

위에서 만든 BoardItem으로 ArrayList를 만들어주고, 샘플데이터를 몇개 넣어봤습니다.

 

 

 

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

ArrayList를 사용해 Adapter를 만들고,

notifyDataSetChange()를 이용해 어댑터와 리사이클러뷰를 갱신시켜줍니다.

 

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

마지막으로 리사이클러뷰에 어댑터를 붙여주고,

레이아웃 매니저를 설정해줍니다.

 

위에서는 LinearLayoutManager를 사용해 설정해주었습니다.

 

 

최종 완성본

 

 

위와 같이 잘 나오는 것을 볼 수 있습니다.

 

이 예제에서는 수직 리사이클러뷰면 알아봤지만,

사용방법에 따라 수평 혹은 그리드 형태로도 만들 수 있습니다.

 

 

 

후기

지금까지 RecylcerView를 한번 만들어 봤습니다.

ListView에 비해 사용방법이 어렵고 복잡하게 느껴질 수 있습니다.

 

그러나, 뷰를 재활용 하기 때문에 자원적으로 더 효율적이며, 더 유연하게 작동합니다.

앱에서 꽤 많이 사용되는 위젯이기 때문에 한 번 사용법을 알아두면 꽤나 요긴하게 쓰입니다.

 

또한, RecylcerView는 ListView와 달리, 아이템 클릭 리스너를 기본적으로 지원하지 않는데,

이와 관련된 내용은 아래 포스팅을 참고해주세요.

https://uknowblog.tistory.com/125

 

profile

Uknow's Lab.

@유노 Uknow

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