我有一个附加到新 ViewPager2 的 FragmentStateAdapter。在之前的 ViewPager 实现中,有多种方法可以实现无限/无限滚动。如何在 ViewPager2 中这样做?
提前致谢。
我有一个附加到新 ViewPager2 的 FragmentStateAdapter。在之前的 ViewPager 实现中,有多种方法可以实现无限/无限滚动。如何在 ViewPager2 中这样做?
提前致谢。
这就是我想出的:
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
,起始位置是Int.MAX_VALUE/2
这样用户可以向前和向后滚动。
要使用 viewpager 2 实现无休止的滑动,我们可以执行以下操作:-
originalList.add(0, lastElement) // last element at the first position
originalList.add(firstElement) // first element at the last
viewpager.setCurrentItem(1, false)
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 中无限滚动/滑动。
我编写了一个准备三个页面的程序,当您从中心页面移动时,页面的内容会移动并返回到中心页面。如果它对你有用,我很高兴。
(我只有 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 会有点困难。
我对android很陌生,我花了一整天的时间阅读我能找到的关于这个问题的所有帖子。我还有一个 FragmentStateAdapter,其中有 3 个 Fragment 附加到 viewPager2。
我的解决方案是覆盖该OnPageChangeCallback
事件。在这里,我将 state 和 currentPosition 保存在 2 个局部变量中;然后,在 中onPageScrolled
,我添加了一个控件来理解:
如果所有这些条件都成立并且我在第一页,那么我会将下一页设置为最后一页,反之亦然。
这是我的代码。我使用 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);
}
});
滚动完成后,您应该返回 view_pager 的第一个或最后一个位置。
看到这个问题 - 更改 ViewPager 以启用无限页面滚动
定义一个扩展 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)
}