아래 두 동영상의 차이점이 뭘까?
왼쪽은 각 항목들이 호롤롤로롤로로 힘없이 넘어간다.
반면 오른쪽 동영상은 한칸씩 딱! 딱! 맞춰서 넘어간다.
이걸 구현하기 위해서 대부분은 ViewPager를 사용할 것이다. 이 상황에서는 맞는 방법이다.
하지만 이런 UI라면?
Grid처럼 한 페이지에 여러 값이 존재하고, 그게 한칸씩 딱딱 맞춰서 넘어가야한다.
그리고 중요한점.
가운데 정렬이 아닌, 왼쪽 정렬이다
이거땜에 개빡쳤었다.
💡 이럴때는 ViewPager를 쓰는것도 나쁘지 않지만, RecyclerView도 활용해보자.
왜 굳이 ViewPager를 안쓰고 RecyclerView를 쓸까?
구현하기가 너무 귀찮았다그래서 RecyclerView를 Grid레이아웃으로 작성하고, Custom해서 VIewPager효과를 내자! 생각했다.
ViewPager 내부 코드를 뜯어보면 애초에 RecyclerView를 커스텀해서 만들었다 ㅋㅋㅋ
즉, ViewPager를 직접 만들어보면서 원리를 익히기 아 주 조 아
그리고 중요한점!
ViewPager 내부에 RecyclerView를 넣을 생각을 하니까 벌써부터 구조가 보기 싫어지고 손발이 벌벌 떨렸다.
👀 어떻게 RecyclerView를 ViewPager처럼 쓸까?
grid레이아웃은 다들 할 수 있을거라고 믿는다. 화이팅!
RecyclerView에는 SnapHelper라는게 존재한다.
쉽게 말해서 ViewPager처럼 한칸씩 움직이게 해주는 그친구다.
그래서 SnapHelper를 선언해주고, RecyclerView를 연결해주면 끝이다. 참 쉽죠?
private lateinit var attentionAdapter: TodayAttentionAdapter
private lateinit var attentionSnapHelper: LinearSnapHelper // 이친구가 오늘의 주인공
private fun initAttentionAdapter() {
attentionAdapter = TodayAttentionAdapter(requireContext())
attentionAdapter.submitList(viewModel.mockTodayAttentionList)
binding.rvTodayAttention.addItemDecoration(
EdgeMarginItemDecoration(
edgeMargin = 24.dpToPx,
itemMargin = 12.dpToPx
)
)
attentionSnapHelper = LinearSnapHelper() // 이케 선언하고
attentionSnapHelper.attachToRecyclerView(binding.rvTodayAttention) // 이케 리사이클러뷰랑 연결
binding.rvTodayAttention.adapter = attentionAdapter
}
이걸 연결하면 끝!
한번 실행시켜 본다면 제일 위에 올려둔 것 처럼 가운데 정렬로 화면에 나타날 것이다.
😢 그러면 왼쪽으로 정렬은 어케해요…?
SnapHelper를 커스텀 하면 됩니다!
class CustomSnapHelper : LinearSnapHelper() {
override fun calculateDistanceToFinalSnap(layoutManager: RecyclerView.LayoutManager, targetView: View): IntArray? {
// 왼쪽 정렬을 위해 거리를 계산
val out = IntArray(2)
if (layoutManager.canScrollHorizontally()) {
out[0] = layoutManager.getDecoratedLeft(targetView) - layoutManager.paddingStart
}
return out
}
override fun findTargetSnapPosition(layoutManager: RecyclerView.LayoutManager?, velocityX: Int, velocityY: Int): Int {
// 기본적인 타겟 포지션을 찾는 로직은 유지
return super.findTargetSnapPosition(layoutManager, velocityX, velocityY)
}
}
calculateDistanceToFinalSnap을 커스텀 → 정렬 위치 조정!