[Android Studio] 리사이클러뷰

hui·2023년 7월 27일

AndroidStudy

목록 보기
3/7

RecyclerView의 정의

RecyclerView란 'A flexible view for providing a limited window into a large data set' 으로
한 화면에 표시할 수 없는 많은 데이터를 스크롤 가능한 리스트로 표시해주는 위젯이다.

리사이클러뷰는 뷰홀더 패턴을 사용하여 화면 밖으로 스크롤된 아이템 뷰를 메모리에 유지하고 재사용할 수 있는데, 이를 통해 불필요한 뷰 객체 생성과 파괴를 줄여 성능과 메모리 사용량을 개선하기 때문에 많은 데이터도 리스트 처럼 담을 수 있는 것이다.

목록을 구성하는데 사용되는 뷰로는 ListView 도 있지만 성능상 최근엔 RecyclerView를 더 선호하는 편이다. 주요클래스로 특징을 살펴보자!

주요클래스

Adapter : 기존의 ListView에서 사용하는 Adapter와 같은 개념으로 데이터와 아이템에 대한 View 생성.
ViewHolder : 재활용 View에 대한 모든 서브 뷰를 보유.
LayoutManager : 아이템 항목을 어떻게 배치하는가를 결정.
ItemDecoration : 아이템에 대한 데코레이션(경계선, 여백, 그림자 등) 을 제공하는 클래스.
ItemAnimation : 아이템 항목이 추가, 삭제되거나 정렬될 때 애니메이션 처리.
  • Adapter : 데이터를 가져와 레이아웃에 적절하게 바인딩하는 역할의 클래스.

    • getItemCount() : 리사이클러뷰에 전달되는 데이터의 개수를 반환.
    • onCreateViewHolder() : 뷰홀더 객체를 생성. 목록 아이템에 사용되는 레이아웃을 인플레이션하고, 뷰홀더 객체를 생성한 후 반환.
    • onBindViewHolder() : 데이터를 뷰에 바인딩. 어댑터는 전달된 데이터를 사용하여 각 위치에 해당하는 목록 아이템의 뷰에 표시되는 값을 업데이트.
  • ViewHolder : 아이템의 뷰(View)를 저장하고 관리하는 도구

    • 아이템에 대한 모든 뷰 객체를 저장해두기 때문에, 뷰 객체를 계속 찾아야 하는 findViewById()를 반복적으로 호출하지 않아도 된다. 목록 아이템을 표시하는 데 필요한 뷰를 빠르게 가져오고 화면에 표시 가능. > 더욱 빠르게 스크롤, 렌더링. 무한 스크롤 구현 가능.
  • LayoutManger

    • 더 다양한 타입의 리스트들을 지원하고, 커스텀할 수 있도록 해준다.

👉 RecyclerView 예제

1) 아이템 레이아웃 생성

item_recycler_view.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="5dp"
    android:paddingVertical="10dp"
    android:paddingHorizontal="10dp"
    android:background="@color/purple"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <TextView
        android:id="@+id/tv_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="이름"
        android:textStyle="bold"
        android:layout_marginLeft="20dp"
        android:textSize="24sp"
        android:textColor="@color/black"
       app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>
    <TextView
        android:id="@+id/tv_age"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="나이"
        android:layout_marginLeft="20dp"
        android:textSize="18sp"
        android:textColor="@color/black"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/tv_name" />

</androidx.constraintlayout.widget.ConstraintLayout>

res > values > color.xml 에서 배경에 넣을 색 값을 추가. (전 연보라색 했습니다!!)

    <color name="purple">#E8CCFF</color>

2) 데이터 클래스 생성

BoardItem.kt

data class BoardItem(val name: String, val age: String)

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

3) 리사이클러뷰 어댑터 생성

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

//    viewGroup : 다른 뷰들을 포함하는 컨테이너 역할의 클래스. (linearLayout, RelativeLayout, FrameLayout..)
//    context : 액티비티, 서비스 컴포넌트가 이를 상속받음 -> 실행앱 정보, 리소스 접근 ..
//    LayoutInflater : 안드로이드에서 XML 레이아웃 파일을 실제 뷰 객체로 인플레이션하는 역할의 클래스

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BoardViewHolder {
        val view = LayoutInflater.from(parent.context)
            .inflate(R.layout.item_recycler_ex, parent, false)
//R.layout.item_recycler_ex <-를 parent.context에서 인플레이션하여 뷰 객체(view) 생성.            
            
        return BoardViewHolder(view)

    }
    
    override fun onBindViewHolder(holder: BoardViewHolder, position: Int) {
        holder.tv_age.text = itemList[position].age
        holder.tv_name.text = itemList[position].name
//    ViewHolder의 tv_age라는 TextView의 텍스트를 itemList에서 해당 position에 있는 아이템의 나이(age)로 설정합니다.
//onCreateViewHolder 는 리사이클러 뷰가 생성될 때만 호출되지만, onBindViewHolder 는 스크롤 할때마다 호출이 된다.
    }
    
    override fun getItemCount(): Int {
        return itemList.count()
    }
//  RecyclerView에 표시할 아이템의 개수를 반환 = 위 클래스에서 매개변수로 받은 itemList 의 길이


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

onCreateViewHolder, BoardViewHolder, getItemCount 클래스를 오버라이딩 합니다.
(RecyclerView.Adapter<BoardAdapter.BoardViewHolder>() 의 기능을 상속받는 "BoardAdapter" 를 사용하기 위함)

onCreateViewHolder -> 아이템 레이아웃과 결합 
onBindBiewHolder -> view 에 내용입력
getItemCount -> 리스트내 아이템 갯수
BoardViewHolder -> 레이아웃 내 View 연결

4) xml 에 리사이클러뷰 넣기

activity_main.xml

<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:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/profile"

        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
        android:orientation="vertical"
        tools:listitem="@layout/item_recycler_ex"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent" />
    <!-- listitem : 리사이클러뷰에 리스트 아이템으로 item_recycler_ex(낱개) 넣음-->

</androidx.constraintlayout.widget.ConstraintLayout>

가로방향으로 배치하려면 vertical을 horizontal로 바꾸면 된다.
만약 격자무늬로 배치하고 싶으면 LinearLayoutManager 대신 GridLayoutManager를 사용.

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

MainActivity.kt

class MainActivity : AppCompatActivity() {

    private lateinit var binding : ActivityMainBinding


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

//        <> : 실제 리스트에 저장될 데이터의 타입을 의미
        val rv_board = binding.profile

        val itemList = ArrayList<BoardItem>()


//      !! :  Kotlin에서 Nullable 타입을 Non-Nullable로 강제로 변환하는 연산자. null 값이 아님을 확신.

        itemList.add(BoardItem("예진", "17세"))
        itemList.add(BoardItem("지민", "17세"))
        itemList.add(BoardItem("예지", "16세"))
        itemList.add(BoardItem("현서", "17세"))
        itemList.add(BoardItem( "소현", "17세"))
        itemList.add(BoardItem( "기준", "29세"))
        itemList.add(BoardItem( "수현", "27세"))
        itemList.add(BoardItem( "상윤", "32세"))

//        ArrayList(itemList) 를 사용해 Adapter를 만든 후, notifyDataSetChange()로 어댑터와 리사이클러뷰를 갱신 시킨다. (다시 그려서 화면에 보여준다)
        val boardAdapter = BoardAdapter(itemList)
        boardAdapter.notifyDataSetChanged()

        rv_board.adapter = boardAdapter
        rv_board.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
//      레이아웃 매니저 설정 = 리사이클러뷰 안에 아이템들을 어떤 방식으로 배치할지를 결정
// 		VERTICAL: 세로배치, HORIZONTAL: 가로배치 / false: 스크롤 역순x

    }
}

마무리

참고자료 : https://uknowblog.tistory.com/29
정리해도 어려운 것 같습니다.. 나중에 binding 활용해서 다시 한 번 도전해볼게요. 완성~!

profile
백엔드 개발자로 변신.

0개의 댓글