簡體   English   中英

如何向 ViewPager2 添加無盡/無限滾動?

[英]How to add endless/infinite scroll to ViewPager2?

我有一個附加到新 ViewPager2 的 FragmentStateAdapter。 在之前的 ViewPager 實現中,有多種方法可以實現無限/無限滾動。 如何在 ViewPager2 中這樣做?

提前致謝。

要使用 viewpager 2 實現無限滑動,我們可以執行以下操作:-

  1. 在開頭添加最后一個元素的副本,在末尾添加第一個元素的副本。
originalList.add(0, lastElement) // last element at the first position
originalList.add(firstElement)   // first element at the last
  1. 設置適配器后,確保將當前項目設置為 1。
viewpager.setCurrentItem(1, false)
  1. 設置適配器后,從 viewpager 組件中提取 recyclerView 並向其添加以下滾動偵聽器。
val recyclerView = viewpager.getChildAt(0) as RecyclerView
val layoutManager = recyclerView.layoutManager as LinearLayoutManager
val itemCount = viewpager.adapter?.itemCount ?: 0
// attach scroll listener
recyclerView.addOnScrollListener(object: RecyclerView.OnScrollListener() {
     override fun onScrolled(
        recyclerView: RecyclerView, dx: Int, dy: Int) {
        super.onScrolled(recyclerView, dx, dy)
        val firstItemVisible 
            = layoutManager.findFirstVisibleItemPosition()
        val lastItemVisible 
            = layoutManager.findLastVisibleItemPosition()
        if (firstItemVisible == (itemCount - 1) && dx > 0) {
            recyclerView.scrollToPosition(1)
        } else if (lastItemVisible == 0 && dx < 0) {
            recyclerView.scrollToPosition(itemCount - 2)
        }
    }
})

在這三個步驟之后,我們可以在 viewpager2 中無限滾動/滑動。

致謝: Viewpager 2 無限滑動

這就是我想出的:

class EndlessScrollAdapter internal constructor(
    fm: FragmentManager,
    lifeCycle: Lifecycle
) : FragmentStateAdapter(fm, lifeCycle) {

    private val items = mutableListOf<YourModel>()
    val firstElementPosition = Int.MAX_VALUE / 2

    fun updateList(list: List<YourModel>) {
        items.apply {
            clear()
            addAll(list)
        }
        notifyDataSetChanged()
    }

    override fun getItemCount(): Int = if (items.isNotEmpty()) Int.MAX_VALUE else 0

    override fun createFragment(position: Int): Fragment = YourPagerFragment(
        items[position.rem(items.size)])
}

在 Activity 或 Fragment 中我們需要調用:

viewPager2.adapter = endlessScrollAdapter
endlessScrollAdapter.apply {
  updateList(yourModelList)
  viewPager2.setCurrentItem(this.firstElementPosition, false)
}

從字面上看,這不是無止境的,但從用戶的角度來看,它是,因為他永遠不會到達邊緣。 ViewPager2 的長度是Int.MAX_VALUE ,開始 position 是Int.MAX_VALUE/2所以用戶可以向前和向后滾動。

我對 android 很陌生,我花了一整天的時間閱讀我能找到的關於這個問題的所有帖子。 我還有一個 FragmentStateAdapter,其中有 3 個 Fragment 附加到 viewPager2。

我的解決方案是覆蓋OnPageChangeCallback事件。 在這里,我將 state 和 currentPosition 保存在 2 個局部變量中; 然后,在onPageScrolled中,我添加了一個控件來理解:

  1. 如果滑動事件開始
  2. 如果新的 position 等於當前的 position。 觀察日志我注意到只有當我嘗試從第一頁向左滾動或從最后一頁向右滾動時它們是相同的。
  3. 如果頁面 position 是第一個或最后一個

如果所有這些條件都成立並且我在第一頁,那么我會將下一頁設置為最后一頁,反之亦然。

這是我的代碼。 我使用 0 和 2 因為我有 3 個片段。

viewPager2.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback()
{
    private int myState;
    private int currentPosition;

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels)
    {
        if (myState == ViewPager2.SCROLL_STATE_DRAGGING && currentPosition == position && currentPosition == 0)
            viewPager2.setCurrentItem(2);
        else if (myState == ViewPager2.SCROLL_STATE_DRAGGING && currentPosition == position && currentPosition == 2)
            viewPager2.setCurrentItem(0);

        super.onPageScrolled(position, positionOffset, positionOffsetPixels);
    }

    @Override
    public void onPageSelected(int position)
    {
        currentPosition = position;

        super.onPageSelected(position);
    }

    @Override
    public void onPageScrollStateChanged(int state)
    {
        myState = state;

        super.onPageScrollStateChanged(state);
    }
});

我寫了一個准備三頁的程序,當你從中心頁面移動時,頁面的內容被移動並且 go 回到中心頁面。 如果對您有用,我很高興。

(我只有 4 個月的編程經驗。所以此代碼僅供參考)

在您的片段或活動中

・・・
private ViewModel viewModel;
private ViewPager2 pager2;
private List<Integer> numbers;
private int currentPosition;

public View onCreateView(@NonNull LayoutInflater inflater,
                         ViewGroup container, Bundle savedInstanceState) {
    ・・・
    pager2.setCurrentItem(1, false);

    ・・・
}
private ViewPager2.OnPageChangeCallback pageChangeCallback = new ViewPager2.OnPageChangeCallback() {
    @Override
    public void onPageSelected(final int position) {
        super.onPageSelected(position);
        currentPosition = position;
    }

    @Override
    public void onPageScrollStateChanged(final int state) {
        super.onPageScrollStateChanged(state);
        //If you moved from center page, repack the contents of the pages and go back to center page.
        if(state == pager2.SCROLL_STATE_IDLE && currentPosition != 1){
            items = viewModel.shiftNumbers(numbers, 2-currentPosition, (currentPosition-1)*3);
            adapter.notifyDataSetChanged();
            pager2.setCurrentItem(1, false);
        }
    }
};

@Override
public void onDestroyView() {
    super.onDestroyView();
    binding = null;
}

在你的視圖模型中

private List<Integer> numbers;

public ViewModel() {

    numbers = new ArrayList<>();

    for (int i = 0; i < 3; i++) {
        numbers.add(i, i-1);
    }
}
public List<Integer> getNumbers(){
return numbers;
}

public List<Integer> shiftNumbers (List<Integer> numbers, int pickPosition, int difference){
   //When moving to page 0 of [0,1,2], the contents of the page 2 are replaced with the contents that should be on page -1. Moving to page 2 is handled in the same way.
    int number = numbers.get(pickPosition);
    number = number+difference;
    //Then repack.
    numbers.remove(pickPosition);
    numbers.add(2-pickPosition,number);
    return numbers;
}

Adapter 和 ViewHolder 可以作為默認值。 當您想要顯示上一頁/下一頁時也可以應用此方法。 但是使用 PageTransformer 會有點困難。

滾動完成后,您應該返回 view_pager 的第一個或最后一個 position。

看到這個問題 - 更改 ViewPager 以啟用無限頁面滾動

定義一個 class 擴展 ViewPager2.OnPageChangeCallback:

class ViewPager2PageChangeCallback(private val listener: (Int) -> Unit) :
        ViewPager2.OnPageChangeCallback() {

    override fun onPageSelected(position: Int) {
        super.onPageSelected(position)
        when (position) {
            0 -> listener.invoke(5). // 0th element is a fake element in your list. When 0th element is opened(from 1 to 0) automatically open last element(5th index)
            6 -> listener.invoke(1). // 6th element is a fake element in your list. When 6th element is opened(from 5 to 6) automatically open first element(1th index)
        }
    }
}

然后在您的活動中創建一個實例。

onCreate(){
    viewPager2PageChangeCallback = ViewPager2PageChangeCallback {
        viewPager2.post {
            viewPager2.setCurrentItem(it, false)
        }
    }
    viewPager2.registerOnPageChangeCallback(viewPager2PageChangeCallback)
}

當活動被銷毀時,從它注銷。

override fun onDestroy() {
    super.onDestroy()
    viewPager2.unregisterOnPageChangeCallback(viewPager2PageChangeCallback)
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM