목차
1. Custom LayoutManager
2. Custom Adapter
3. Nested RecyclerView Scrolling
Recyclerview는 많은 데이터를 제한된 영역 내에서 유연하게 스크롤 가능한 리스트로 표시해 주는 위젯입니다. Recyclerview는 뷰를 재활용하므로 앱 성능과 메모리 관리 측면에서도 매우 유용하며, 대규모 데이터를 효율적으로 쉽게 표시할 수 있습니다. 안드로이드 UI 툴킷의 중요한 구성 요소이며 많은 안드로이드 앱에서 널리 사용되고 있습니다.
Recyclerview를 사용할 때의 이점 중 하나는 커스텀이 매우 용이하다는 것입니다. 이 포스팅에서는 사용자의 특정 요구에 맞게 커스텀 하는 몇 가지 방법을 살펴보겠습니다.
Custom LayoutManager
Recyclerview를 커스텀 하는 한 가지 방법은 LayoutManager를 커스텀 하는 것입니다. LayoutManager는 아이템의 위치를 지정하고 측정하며 사용자에게 더 이상 표시되지 않는 항목을 재활용할 시기를 결정합니다.
다음은 Recycler View에서 중앙 item을 기준으로 확대/축소하는 CenterZoomLayoutManager 예시입니다.
- LinearLayoutManager를 상속하는 CenterZoomLayoutManager 클래스를 생성합니다.
- generateDefaultLayoutParams()에서 LayoutParams 개체를 생성합니다.
- canScrollHorizontally()을 true로 설정해 수평 스크롤을 지원합니다.
- scrollHorizontallyBy()에서 수평 스크롤에 대한 동작을 구현합니다.
- 추가로 smoothScrollToPosition()에서 스크롤 속도를 커스텀 합니다.
- 마지막으로 Recyclerview에 setLayoutManager로 적용합니다.
이렇게 하면 중앙 item을 기준으로 확대/축소되는 효과가 Recyclerview에 적용됩니다.
추가로 가운데 스냅 효과를 주기 위해 GravitySnapHelper 클래스를 생성해 Recyclerview에 적용합니다. GravitySnapHelper는 리스트가 스크롤 될 때 아이템을 화면 중앙으로 스냅 하는 효과를 주기 위한 클래스입니다.
다음은 GravitySnapHelper 예시입니다.
Gravity.CENTER로 스크롤 효과 기준을 가운데로 설정하고, attachToRecyclerView를 사용해 Recyclerview에 적용합니다.
val snapHelper = GravitySnapHelper(Gravity.CENTER)
snapHelper.setScrollMsPerInch(25f) //scroll speed
snapHelper.attachToRecyclerView(recyclerView)
Custom Adapter
Adapter는 Recyclerview의 필수 항목으로 아이템 뷰를 생성하고 데이터를 바인딩 하는 역할을 합니다. Adpater를 커스텀 해 복잡한 레이아웃이 포함된 Recyclerview를 만들 수 있습니다.
다음은 중첩 Recyclerview를 만들기 위한 Adapter 커스텀 예시입니다. 수직 Recyclerview 내부에 여러 뷰 타입의 수평 Recyclerview가 배치된 경우입니다.
ParentAdapter와 ChildAdapter가 존재하며, ParentAdapter에서 데이터 뷰 타입에 따라 여러 개의 ViewHolder를 생성하고 바인드 합니다.
getItemViewType에서 데이터의 뷰 타입을 구분합니다.
onCreateViewHolder에서 뷰 타입에 따라 뷰 홀더를 생성합니다.
onBindViewHolder에서 뷰 타입에 따라 각 뷰 홀더에 바인드 합니다.
ChildAdapter는 여러 개로 각각 사용해도 됩니다. 예제에서는 하나의 ChildAdapter를 이용했습니다. ChildAdapter item의 width와 layoutManager를 다르게 설정해 여러 레이아웃 타입을 만들었습니다.
추가로 RecycledViewPool을 이용해 스크롤 성능을 개선합니다.
RecycledViewPool은 뷰 계층에서 일시적으로 제거된 뷰를 위한 저장소 풀입니다. 리스트의 각 항목에 대해 재사용할 수 있도록 하여 RecyclerView의 성능을 향상시키는 데 사용됩니다. 성능 향상을 위해 중첩된 Recyclerview에 하나의 RecycledViewPool을 공유합니다.
또한 LinearLayoutManager에 initialPrefetchItemCount로 중첩된 Recyclerview에서 미리 가져와야 하는 내부 항목 수를 설정합니다. 기본 값 2 대신 설정한 항목 수만큼 미리 바인딩 작업을 수행해 스크롤 될 때 버벅거림을 방지할 수 있습니다.
(자세한 소스 코드를 보시려면 아래 링크를 클릭해 주세요.)
Nested RecyclerView Scrolling
중첩된 Recyclerview의 경우 스크롤이 잘되지 않는 경우가 발생할 수 있습니다. 부모 Recyclerview에서 스크롤 이벤트를 해결하는 동안 중첩된 다른 Recyclerview를 스크롤 하려고 하면 상호 간 터치 이벤트 간섭으로 인해 스크롤 동작이 잘 안 먹힐 수 있습니다. 이러한 경우 onInterceptTouchEvent를 이용해 스크롤을 개선할 수 있습니다.
onInterceptTouchEvent() 메서드는 ViewGroup 표면에서 터치 이벤트가 감지될 때마다 호출됩니다. true를 반환하면 MotionEvent가 가로채기 되며, 이는 하위 요소로 전달되지 않고 상위 요소의 onTouchEvent() 메서드에 전달됨을 의미합니다.
MotionEvent.ACTION_DOWN : 손가락을 눌렸을 때
MotionEvent.ACTION_MOVE : 손가락을 누르고 움직였을 때
MotionEvent.ACTION_UP : 손가락 누른 것을 땠을 때
아래 예시는 onInterceptTouchEvent를 커스텀 한 OrientationAware RecyclerView입니다. 사용자가 손가락을 움직일 때 스크롤 방향이 Recyclerview 방향과 일치하면 터치 이벤트를 가로채고 그렇지 않으면 가로채지 않습니다.
방문해 주셔서 감사합니다^^
잘 읽으셨다면 좋아요❤ 꾹!
오늘도 좋은 하루 보내세요 :)
'Main' 카테고리의 다른 글
[Android] 이미지 로드 최적화 (10) | 2023.01.06 |
---|---|
[Android] 다양한 폼 팩터를 위한 UI 개발 (4) | 2022.12.30 |
[Android] Github Actions으로 CI/CD 구축 (8) | 2022.12.21 |
[Android] Room을 활용해 Android 오프라인 캐시 구현 (0) | 2022.12.06 |
[Android] Service를 활용한 Timer 개발 (0) | 2022.11.30 |
댓글