RecyclerView를 사용하면 대량의 데이터 셋을 효율적으로 표시할 수 있음, 데이터를 제공하고 아이템이 어떻게 표시되는지 정의하면 RecyclerView 라이브러리가 요소가 필요할 때 동적으로 생성해줌
이름에서 알 수 있듯, RecyclerView 는 개별 요소를 재활용함, 아이템이 화면 밖으로 스크롤될때 RecyclerView 는 그 뷰를 파괴하지 않음, 대신 RecyclerView 는 화면으로 스크롤되는 새로운 아이템을 위해 뷰를 재사용함, 이런 점에서 RecyclerView 는 앱의 반응성과 성능을 개선하고 전원 소비를 줄여줌
노트:
RecyclerView는 클래스와 동시에 이를 포함하는 라이브러리의 이름입니다. 이 페이지에서RecyclerView를 코드 블록에 표시하면 라이브러리의 클래스를 의미합니다.
RecyclerView 는 데이터에 대응되는 뷰를 포함하는 ViewGroup 임, 이는 RecyclerView 가 결국 뷰라는 뜻으로 다른 UI 요소를 레이아웃에 추가하는 방법 그대로 추가할 수 있다는 뜻임
리스트의 각각의 요소는 뷰 홀더 객체임, 뷰 홀더가 생성될 때는 데이터를 가지고 있지 않음, 뷰 홀더가 생성되고 나면 RecyclerView 에서 데이터와 연결해줌, 뷰 홀더는 RecyclerView.ViewHolder 를 상속받아 정의할 수 있음
RecyclerView 는 어댑터의 메소드를 호출해 뷰를 요청하고 뷰를 데이터와 연결함, 어댑터는 RecyclerView.Adapter 를 상속받아 정의할 수 있음
레이아웃 매니저는 리스트의 개별 요소를 정렬함, 라이브러리에서 제공되는 레이아웃 매니저를 사용하거나 직접 정의해서 사용할 수 있음, 레이아웃 매니저는 라이브러리의 LayoutManager 추상 클래스를 기반으로 만들어짐
리스트나 그리드를 어떻게 표시할지 결정함, 일반적으로 RecyclerView 라이브러리의 표준 레이아웃 매니저를 사용함
리스트의 각 요소가 어떻게 표시되고 동작할지 설계함, 설계에 따라 ViewHolder 클래스를 상속해 만듬, 이렇게 만든 ViewHolder 는 리스트 아이템을 위한 모든 기능을 제공해야 함, 뷰 홀더는 View를 감싸는 클래스이고 그 뷰는 RecyclerView 에 의해 관리됨
ViewHolder 와 데이터를 연결하는 Adapter 를 정의함
LayoutManager 클래스에 의해 정렬됨, RecyclerView 라이브러리는 대부분의 레이아웃을 처리하는 세 개의 레이아웃 매니저를 제공함LinearLayoutManager 는 1차원 리스트로 아이템을 정렬함GridLayoutManager 는 2차원 그리드로 아이템을 정렬함GridLayoutManager 는 각 행의 모든 요소를 같은 너비와 높이로 만듬, 행마다 높이는 다르게 가질 수 있음GridLayoutManager 는 각 열의 모든 요소를 같은 너비와 높이로 만듬, 열마다 너비는 다르게 가질 수 있음StaggeredGridLayoutManager 는 GridLayoutManager 와 비슷하지만 수직 그리드의 경우 행의 아이템에 대해 모두 같은 높이, 수평 그리드의 경우 열의 아이템에 대해 모두 같은 너비를 요구하지 않음, 그 결과로 같은 행이나 열에 있는 아이템들이 어긋나도록 배치될 수 있음레이아웃을 결정하고 나면 Adapter 와 ViewHolder 를 구현해야 함, 이 두 클래스는 데이터를 어떻게 표시할 것인지 정할 때 같이 사용됨, ViewHolder 는 리스트의 개별 아이템을 위한 레이아웃을 포함하는 View 의 래퍼 클래스임, Adapter 는 필요한만큼 ViewHolder 객체를 만들고 이 뷰들을 위한 데이터를 설정함, 뷰에 데이터를 연결하는 작업을 binding 이라고 함
어댑터를 정의할 때 다음 세가지 주요 메소드를 오버라이드해야 함
onCreateViewHolder() : RecyclerView 가 새 ViewHolder 를 생성해야 할 때 호출함, 이 메소드는 ViewHolder 와 연결된 View 를 생성하고 초기화함, 하지만 뷰의 내용을 채우지는 않음, 즉, ViewHolder 는 아직 특정 데이터와 연결되지 않은 상태임onBindViewHolder() : RecyclerView 가 ViewHolder 와 데이터를 연결할 때 이 메소드를 호출함, 이 메소드는 적절한 데이터를 찾고 그 데이터를 사용해 뷰 홀더의 레이아웃을 채움, 예시로 RecyclerView 가 이름의 리스트를 표시한다면 이 메소드는 리스트에서 적절한 이름을 찾고 뷰 홀더의 TextView 위젯을 채움getItemCount() : RecyclerView 가 데이터셋의 크기를 얻을 때 사용하는 메소드, 예시로 주소책 앱이라면 이 메소드는 주소의 총 갯수가 반환될 수 있음, 이 메소드는 더이상 표시할 아이템이 없는지 결정할 때 사용됨다음은 간단한 어댑터와 데이터의 리스트를 표시하는 중첩된 ViewHolder 의 일반적인 예제임, 이 경우에 RecyclerView는 간단한 텍스트의 리스트를 표시함, 어댑터에 ViewHolder 요소를 위한 문자열의 배열이 전달됨
class CustomAdapter(private val dataSet: Array<String>) :
RecyclerView.Adapter<CustomAdapter.ViewHolder>() {
/**
* 사용하는 뷰 유형의 참조를 제공합니다.
* (사용자 정의 ViewHolder)
*/
class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val textView: TextView
init {
// ViewHolder의 뷰를 위한 클릭 리스너 정의
textView = view.findViewById(R.id.textView)
}
}
// 새로운 뷰 생성 (레이아웃 관리자에 의해 호출됨)
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): ViewHolder {
// 리스트 아이템의 UI를 정의하는 새로운 뷰를 생성
val view = LayoutInflater.from(viewGroup.context)
.inflate(R.layout.text_row_item, viewGroup, false)
return ViewHolder(view)
}
// 뷰의 내용 교체 (레이아웃 관리자에 의해 호출됨)
override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
// 데이터 셋에서 해당 위치에 있는 요소를 가져와
// 뷰의 내용을 해당 요소로 교체함
viewHolder.textView.text = dataSet[position]
}
// 데이터 셋의 크기를 반환 (레이아웃 관리자에 의해 호출됨)
override fun getItemCount() = dataSet.size
}
text_row_item.xml 파일을 가지고 있음<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="@dimen/list_item_height"
android:layout_marginLeft="@dimen/margin_medium"
android:layout_marginRight="@dimen/margin_medium"
android:gravity="center_vertical">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/element_text"/>
</FrameLayout>
RecyclerView 를 어떻게 사용하는지 보여줌class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val dataset = arrayOf("January", "February", "March")
val customAdapter = CustomAdapter(dataset)
val recyclerView: RecyclerView = findViewById(R.id.recycler_view)
recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.adapter = customAdapter
}
}
다음 단계를 따라해 RecyclerView 를 위한 엣지 투 엣지 디스플레이를 활성화함
enableEdgeToEdge() 를 호출해 하위 호환 가능한 엣지 투 엣지 디스플레이를 설정함
만약 리스트 아이템이 시스템 바를 덮는다면 RecyclerView 에 inset을 적용함, android:fitsSystemWindows 를 true 로 설정하거나 ViewCompat.setOnApplyWindowInsetsListener 를 사용해 적용할 수 있음
RecyclerView 에 android:clipToPadding 을 false 로 설정해 리스트 아이템이 시스템 바 밑에 그려질 수 있도록 허용해야 함
RecyclerView 에 엣지 투 엣지 디스플레이가 비활성화(왼쪽)된 것과 활성화(오른쪽)된 것을 보여주는 영상
inset을 설정하는 코드 예시
ViewCompat.setOnApplyWindowInsetsListener(
findViewById(R.id.my_recycler_view)
) { v, insets ->
val innerPadding = insets.getInsets(
WindowInsetsCompat.Type.systemBars()
or WindowInsetsCompat.Type.displayCutout()
// EditText를 사용한다면
// "or WindowInsetsCompat.Type.ime()"
// 도 추가해 IME를 열었을 때에도 포커스를 유지함
)
v.setPadding(
innerPadding.left,
innerPadding.top,
innerPadding.right,
innerPadding.bottom)
insets
}
RecyclerView를 적용하는 XML 예시
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/my_recycler_view"
android:clipToPadding="false"
android:layout_width="match_parent"
android:layout_height="match_parent" />
원문: https://developer.android.com/develop/ui/views/layout/recyclerview