여기어때 메인 화면.gif
우리는 UX 요구사항에 맞춰 위와 같은 ViewPager 를 개발할 필요가 있습니다.😱
과연 어떻게 만들까요?
Q. 양 옆이 미리보이는 ViewPager 는 어떻게 만들 수 있을까요?
Q. 어떤 설정이요?
ItemDecoration
과 ViewPager2 의 setPageTransformer
를 이용하면 됩니다.Q. 더 간단한 방법 없나요?
먼저, Item이 3개가 있는 ViewPager 를 생각해봅시다.
ViewPager 는 Item View 의 높이 너비가 Match_parent 가 되어야 합니다.
따라서, ViewPager의 너비를 모두 채우는 Item 이 될 수 밖에 없습니다.
그렇다면 어떻게 해야할까요?
Item View 에 padding 을 정의하거나, ItemDecoration 으로 아이템 사이의 Margin 을 지정합니다.
우리는 ItemDecoration 을 통해 아이템 너비를 지정하겠습니다.
우선, Item 의 왼쪽 오른쪽 마진을 지정할 ItemDecoration 을 정의합니다.
private class PageDecoration(private val margin: Int): RecyclerView.ItemDecoration() {
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
outRect.left = margin
outRect.right = margin
}
}
이를 ViewPager 에 설정해줍니다.
private fun initViewPager(itemMargin: Int) {
val decoration = PageDecoration(itemMargin)
binding.viewPager.addItemDecoration(decoration)
}
이렇게 적용을 하면 left, right 마진이 설정된 ViewPager 를 볼 수 있습니다.
이제 1st
와 3rd
가 화면에 보이도록 2nd
에 가깝게 붙이고 싶습니다.
어떻게 할까요?
바로, ViewPager2 의 setPageTransformer
를 사용하면 됩니다.
private fun initViewPager(itemMargin: Int) {
// ..
viewPager.setPageTransformer { page, position ->
// ..
}
}
setPageTransformer
메서드는 PageTransFormer
인터페이스를 인자로 전달받는 메서드입니다.
public interface PageTransformer {
void transformPage(@NonNull View page, float position);
}
PageTransformer
의 transformPage
메서드는 ViewPager 가 스크롤되어 각 아이템의 위치가 변경될 때 마다 호출되는 콜백 메서드입니다.
transformPage
의 position
은 현재 포커스된 가운데 아이템은 0f, 이를 기준으로 왼쪽 아이템은 음수값, 우측 아이템은 0보다 큰 양수값이 전달됩니다.
이를 이용해, 인자로 넘어오는 Page 의 position
를 계산하여 View
의 위치를 변경 할 수 있습니다.
최종 적용된 코드는 아래와 같습니다.
// 인자 `previewWidth` 는 미리 보여야 하는 양옆 아이템의 너비입니다.
private fun initViewPager(previewWidth: Int, itemMargin: Int) {
val decoMargin = previewWidth + itemMargin
val pageTransX = decoMargin + previewWidth
val decoration = PageDecoration(decoMargin)
binding.viewPager.also {
it.offscreenPageLimit = 1
it.addItemDecoration(decoration)
it.setPageTransformer { page, position ->
page.translationX = position * - pageTransX
}
}
}
initViewPager
메서드를 설명하자면,
decoMargin
은 적용할 아이템 사이 마진 값과 미리 보여야 하는 아이템 너비를 더하여 적용합니다.View.translationX
메서드를 통해 Item View 들의 위치를 변경합니다.position
와 음수값 pageTransX
를 곱하여 적용합니다. (position
이 양수인 경우 왼쪽으로 옮기기 위해서 음수 값, 음수인 경우 오른쪽으로 옮기기 위해 양수 값이 필요하므로 음수값 pageTransX
를 곱해줍니다.)pageTransX
는 각 아이템이 decoMargin * 2
만큼 떨어져 있으므로, decoMargin
과 itemMargin
을 더하여 itemMargin
만큼만 보이도록 설정합니다.위 구현 방식이 귀찮거나, 여러 화면에서 쓰여 Custom View 로써 사용해야하는 사람이 있을겁니다.
이런 분들을 위해 라이브러리를 배포했습니다!!👏
유용하셨다면 🌠STAR 를 꾹.. 눌러주세요. 큰 힘이 됩니다!🔥