[Android] 양 옆이 미리보이는 ViewPager2 만들기

킹정인·2023년 7월 6일
1
post-thumbnail

여기어때 메인 화면

여기어때 메인 화면.gif


우리는 UX 요구사항에 맞춰 위와 같은 ViewPager 를 개발할 필요가 있습니다.😱
과연 어떻게 만들까요?

📋결론 요약

Q. 양 옆이 미리보이는 ViewPager 는 어떻게 만들 수 있을까요?

  • View Pager2 에 몇가지 설정을 추가해서 만들 수 있습니다.

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 를 볼 수 있습니다.

이제 1st3rd 가 화면에 보이도록 2nd 에 가깝게 붙이고 싶습니다.
어떻게 할까요?

바로, ViewPager2 의 setPageTransformer 를 사용하면 됩니다.

    private fun initViewPager(itemMargin: Int) {
        // ..
		viewPager.setPageTransformer { page, position ->
			// ..
		}
    }

setPageTransformer 메서드는 PageTransFormer 인터페이스를 인자로 전달받는 메서드입니다.

    public interface PageTransformer {
        void transformPage(@NonNull View page, float position);
    }

PageTransformertransformPage 메서드는 ViewPager 가 스크롤되어 각 아이템의 위치가 변경될 때 마다 호출되는 콜백 메서드입니다.

transformPageposition 은 현재 포커스된 가운데 아이템은 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 메서드를 설명하자면,

  • ItemDecoration 으로 설정하는 마진 값 decoMargin 은 적용할 아이템 사이 마진 값과 미리 보여야 하는 아이템 너비를 더하여 적용합니다.

  • View.translationX 메서드를 통해 Item View 들의 위치를 변경합니다.
  • View 의 위치는 position 와 음수값 pageTransX 를 곱하여 적용합니다. (position 이 양수인 경우 왼쪽으로 옮기기 위해서 음수 값, 음수인 경우 오른쪽으로 옮기기 위해 양수 값이 필요하므로 음수값 pageTransX 를 곱해줍니다.)
  • pageTransX 는 각 아이템이 decoMargin * 2 만큼 떨어져 있으므로, decoMarginitemMargin 을 더하여 itemMargin 만큼만 보이도록 설정합니다.

📚라이브러리

위 구현 방식이 귀찮거나, 여러 화면에서 쓰여 Custom View 로써 사용해야하는 사람이 있을겁니다.
이런 분들을 위해 라이브러리를 배포했습니다!!👏

🔗GitHub 링크

유용하셨다면 🌠STAR 를 꾹.. 눌러주세요. 큰 힘이 됩니다!🔥

profile
🕶안드로이드 개발자입니다! 🕶

0개의 댓글