Android ViewPager로 무한 스크롤 가능

이전에 iOS의 UIScrollView에서 페이지별 무한 스크롤 가능 이라는 기사를 써 안드로이드에서는 어떻게 할 것인가라고 생각했습니다. 조금 조사해 보았더니, Looping/Infinite ViewPager 라고 하는 기사가 돈피샤였습니다. 영어 기사라고 하는 것과, 데이터의 갱신에 대해서는 접하고 있지 않다(조금 유스 케이스가 다르다), 라고 하는 것으로 여기에 정리해 보겠습니다.

아이디어



ViewPager에서 5페이지의 공간을 준비합니다.

[0][1][2][3][4]
  • 처음은 1 페이지째로부터 시작합니다.
  • 페이지 0에 도착하면 세 번째 페이지로 날아갑니다.
  • 네 번째 페이지에 도착하면 첫 번째 페이지로 날아갑니다.

  • 이렇게 하면 5페이지분의 공간의 가장자리에 침착하지 않으므로 항상 좌우로 스크롤할 수 있는 상태가 됩니다.

    이 때, 데이터의 갱신에 대해서도 생각하지 않으면 안됩니다. 위의 2 단계에서 0 페이지에서 3 페이지로 날 때 현재 데이터에서 뒤쪽 3 개를 삭제하고 이전 3 개를 보충합니다.



    마찬가지로 3단계에서 네 번째 페이지에서 첫 번째 페이지로 날 때 현재 데이터에서 이전 세 개를 제거하고 뒤쪽 세 개를 보충합니다.



    코드



    PagerAdapter 서브 클래스 구현



    콜백의 구현은 매우 보통입니다. 총 페이지 수는 5이므로 getCount()에서는 5를 반환합니다.
        private var dataList = ... // データリスト
    
        ...
    
        override fun isViewFromObject(view: View, `object`: Any): Boolean {
            return view == `object`
        }
    
        override fun getCount(): Int {
            return 5
        }
    
        override fun instantiateItem(container: ViewGroup, position: Int): View {
            val view = ... // Layout から inflate
    
            val dataItem = dataList.get(position)
    
            // set dataItem to the view
            view.setData(data.get(position))
    
            container.addView(view)
    
            return view
        }
    
        override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) {
            container.removeView(`object` as View)
        }
    

    그런 다음 데이터 업데이트를 위해 다음과 같은 사용자 지정 메서드를 준비합니다.
        fun initializeData() {
            dataList.clear()
    
            for (i in 0 until 5) {
                dataList.add(...) // 初期データの設定
            }
        }
    
        fun forwardData() {
            for (i in 0 until 3) {
                imageList.removeAt(0)
            }
    
            for (i in 0 until 3) {
                imageList.add(...) // 後データの補填
            }
        }
    
        fun rewindData() {
            for (i in 0 until 3) {
                imageList.removeAt(5 - i - 1)
            }
    
            for (i in 0 until 3) {
                imageList.add(0, ...) // 前データの補填
            }
        }
    

    Activity (또는 Fragment) 측 구현


        // adapter は PagerAdapter サブクラスのインスタンス
        viewPager.adapter = adapter
        // listener は ViewPager.OnPageChangeListener サブクラスのインスタンス。詳細は後述。
        viewPager.addOnPageChangeListener(listener)
        // 最初は 1ページ目から始める。
        viewPager.setCurrentItem(1, false)
    

    listener 는 ViewPager.OnPageChangeListener 서브 클래스의 인스턴스로, 이 구현의 간입니다. 페이지가 바뀌었다는 이벤트를 잡아, 필요에 따라서 다른 페이지로 날아간다고 하는 구현을 여기에서 실시합니다.
        val listener: ViewPager.OnPageChangeListener = object: ViewPager.OnPageChangeListener {
    
            private var jumpPosition = -1;
    
    
            override fun onPageScrolled(
                position: Int,
                positionOffset: Float,
                positionOffsetPixels: Int
            ) {
                // 何もしない
            }
    
            override fun onPageSelected(position: Int) {
                if (position == 0) {
                    jumpPosition = 3
    
                    adapter.rewindData() // 先ほど用意した、前データの補填 method
                } else if (position == 4) {
                    jumpPosition = 1;
    
                    adapter.forwardData() // 先ほど用意した、後データの補填 method
                }
            }
    
            override fun onPageScrollStateChanged(state: Int) {
                //アニメーションが終わるのを待ってから飛ぶ。
                // onPageSelected(int position) でやると、スクロールアニメーションがキャンセルされてしまう。
                if (state == ViewPager.SCROLL_STATE_IDLE && jumpPosition >= 0) {
                    view!!.viewPager.setCurrentItem(jumpPosition, false);
                    jumpPosition = -1;
                }
            }
        }
    

    결과



    이런 식으로 영원히 스크롤하는 화면을 만들 수 있습니다.



    정리와 고찰



    iOS에서 UIScrollView를 사용하면 모든 스크롤 이벤트를 포착하여 페이지를 조정할 수 있었으므로 준비하는 페이지는 3 페이지로 끝났습니다. 하지만, 이번 ViewPager 그럼, 잡히는 것은 페이지에 스냅했을 때의 이벤트만으로, 스크롤 도중의 이벤트를 받을 수 없기 때문에, 5 페이지가 필요. iOS 하지만 UIPageViewController 뭔가를 사용하면, 똑같은 발상으로 5 페이지가 필요하게 된다고 생각합니다.

    기사의 내용을 포함한 소스 코드는 여기 입니다.

    좋은 웹페이지 즐겨찾기