📌 RecyclerView 란?
https://developer.android.com/guide/topics/ui/layout/recyclerview
RecyclerView는 개발자가 각 항목의 모양을 정의하고 대량의 데이터 목록을 화면에 출력해주고 동적으로 표현해 주는 뷰 그룹이다. 비슷한 기능을 갖는 ListView을 사용하지 않고 RecyclerView을 사용하는 이유는 재사용성이다. ListView는 스크롤이 화면에 벗어나면 뷰를 제거하고 새로 보여줄 뷰를 항목 수만큼 findViewById이나 뷰 바인딩을 통하여 각 뷰를 불러와서 사용해야 하는데 매우 비효율적인 방법이다.
따라서 롤리팝(5.0) 버전이 나오면서 ListView보다 유연하고 성능이 향상된 RecyclerView가 발표되었다. RecyclerView는 이름에서 알 수 있듯이 ViewHolder을 통해 만든 객체를 제거하지 않고 재사용하기 때문에 재사용성 부분에서 더욱 효율적이다. 이렇게 뷰를 재사용하면 앱의 응답성을 개선하고 전력 소모를 줄이기 때문에 성능이 개선된다.
아래에서 보면 100개의 아이템이 있다면 100개의 아이템을 모두 생성해야하는 리스트뷰와 달리 리사이클러 뷰는 화면에 보이는 10개 정도의 아이템으로 객체를 재활용하며 계속 사용할 수 있다.
RecyclerView 의 주요 클래스
ViewHolder
각각의 뷰를 보관하는 Holder 객체이다.
Item View 들을 재활용하기 위해 각 요소를 저장해 두고 사용한다.
아이템 생성시 뷰 바인딩은 한 번만 하게 되며, 그 바인딩된 객체를 그대로 가져다 사용하여 성능 부분에서 효율성을 올려준다.
LayoutManager
아이템의 배치를 담당
LinearLayoutManager - 가로 / 세로
GridLayoutManager - 그리드 형식
StaggeredGridLayoutManager - 지그재그형의 그리드 형식
Adapter
뷰를 뷰의 데이터에 바인딩한다.
📌 RecyclerView 만들기
리사이클러뷰에 반복될 아이템의 View로 사용될 Layout을 하나 추가해준다.
color_square.xml
<?xml version="1.0" encoding="utf-8"?>
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/imageView"
android:layout_width="80dp"
android:layout_height="80dp" />
📌 RecyclerAdapter 클래스 만들기
package com.example.photos
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.ImageView
import androidx.recyclerview.widget.RecyclerView
import com.example.photos.databinding.ColorSquareBinding
class RecyclerAdapter(private var dataset: MutableList<Int>) : RecyclerView.Adapter<RecyclerAdapter.ViewHolder>() {
class ViewHolder(binding: ColorSquareBinding) : RecyclerView.ViewHolder(binding.root) {
val imageView: ImageView = binding.imageView
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding = ColorSquareBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return ViewHolder(binding)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.imageView.setBackgroundColor(dataset[position])
}
override fun getItemCount(): Int {
return dataset.size
}
}
위의 코드를 보면 우선 ViewHolder 클래스에 color_square.xml 에서 지정해준 imageView를 지정해준다.
이때 뷰 바인딩을 이용해 주기 위해 Nested Class로 설정해 둔 ViewHolder 클래스의 생성자에 ColorSquareBinding 타입의 binding을 지정해두고, 상속받고 있는 RecyclerView.ViewHolder 에도 binding.root를 인자로 넣어준다.
이제 RecyclerView.Adapter 를 상속받았을 때 기본적으로 구현해주어야 하는 메서드들을 오버 라이딩해주고 구현해준다.
- onCreateViewHoder() : 항목에 사용할 View을 생성하고 ViewHoder을 반환한다.
- onBindViewHolder() : 항목 뷰에 데이터를 연결한다.
- getItemCount() : 아이템의 개수를 가져온다.
나는 랜덤한 여러 개의 색깔을 MutableList<Int>로 가져와서 뿌려주기 위해 RecyclerAdapter 클래스의 생성자에 MutableList<Int> 타입의 dataset이라는 이름으로 프로퍼티를 가져와서 필요한 부분에 각각 적용시켜 주었다.
📌 activity_main.xml 에 RecyclerView 추가하기
<?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/constraintlayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/button_permission"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/permission"
app:layout_constraintEnd_toStartOf="@+id/button_gallery"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/button_gallery"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/gallery"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/button_permission"
app:layout_constraintTop_toTopOf="parent" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/button_gallery">
</androidx.recyclerview.widget.RecyclerView>
</androidx.constraintlayout.widget.ConstraintLayout>
(여기서 상위 두 버튼은 해당 포스트와 관련 없는 버튼이다.)
이때 RecyclerView 에 id 값을 추가하는 것을 까먹지 말도록 하자.
📌 MainActivity 와 RecyclerAdapter 연결해주기
MainActivity
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
val colorList: MutableList<Int> = mutableListOf()
for (i in 1..40) {
colorList.add(Color.rgb(Random.nextInt(0, 255), Random.nextInt(0, 255), Random.nextInt(0, 255)))
}
binding.recycler.adapter = RecyclerAdapter(colorList)
binding.recycler.layoutManager = GridLayoutManager(this, 4)
binding.recycler.clipToPadding = false
binding.recycler.clipChildren = false
binding.recycler.addItemDecoration(ItemDecoration())
}
}
MainActivity 도 마찬가지로 뷰 바인딩 처리를 해주었다. 혹시 뷰 바인딩에 관한 내용이 궁금하다면 아래 포스팅을 참고하기 바란다.
https://jminie.tistory.com/141
우선 랜덤한 40개의 색을 만들기 위해 rgb와 Random 클래스를 이용해서 colorList를 만들어주었다. 이는 앞서 만든 RecyclerAdapter 클래스의 생성자 위치에 들어가게 된다.
binding.recycler.adapter = RecyclerAdapter(clolorList) 이 부분이 MainAciticity의 RecyclerView와 RecyclerAdapter를 연결해주는 부분이다.
그 이후에는 한 줄에 몇 개씩 보여줄 것인지, 어떤 간격으로 보여줄 것인지를 나타낸 것으로 본인이 원하는 디자인으로 커스터마이징하면 된다.
📱 결과물
Reference:
https://yunaaaas.tistory.com/43
https://daldalhanstory.tistory.com/224
https://woovictory.github.io/2019/01/03/Android-Diff-of-ListView-and-RecyclerView/
'Android' 카테고리의 다른 글
안드로이드 [Kotlin] - RecyclerView에서 ListAdapter와 DiffUtil 사용기 (0) | 2022.03.27 |
---|---|
안드로이드 [Kotlin] - LiveData로 계산기 만들기 (0) | 2022.03.27 |
안드로이드 [Kotlin] - Activity에서 Fragment 로 drawable 전송 (ViewPager2, Tablayout 이용) (0) | 2022.02.27 |
안드로이드 [Kotlin] - TextView & Button (0) | 2022.02.20 |
안드로이드 [Kotlin] - 뷰 바인딩 (View Binding) (0) | 2022.02.20 |