androID系统提供的VIEwPager标准方式是左右可以自由滑动,但是滑动到最左边的极限位置是第一个page,滑动到最右边的位置是最后一个page,当滑动到最左或者最右时候,就不能再滑动/滚动了,这是AndroID系统默认的VIEwPager实现方式。
但是有些情况下开发者可能希望VIEwPager能够智能的无限循环滚动回绕,比如现在总共有编号1,2,3,4,5的5个Page。
(1)当用户手指从右往左滚动到最右边/最后面的页面5时候,如果此时用户继续拖住VIEwPager往左边滑动,那么VIEwPager将回绕、循环到第一个Page -> 1,接着就是2,5;
(2)反过来,如果当用户手指从左往右,滑到最左边的第一个Page:1时候,如果此时继续拖住VIEwPager继续从左往右滑动,那么将回绕到5,接着就是4,1.
我们把这种VIEwPager称之谓“无限循环滚动回绕”的VIEwPager。
这种类型的VIEwPager网上有较多实现方式,现在给出一个流程较广的代码实现。
写一个测试的MainActivity.Java:
package zhangphil.demo;import java.util.Random;import androID.app.Activity;import androID.graphics.color;import androID.os.Bundle;import androID.support.v4.vIEw.PagerAdapter;import androID.vIEw.Gravity;import androID.vIEw.VIEw;import androID.vIEw.VIEwGroup;import androID.Widget.TextVIEw;public class MainActivity extends Activity { @OverrIDe protected voID onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentVIEw(R.layout.activity_main); LoopVIEwPager vIEwpager = (LoopVIEwPager) findVIEwByID(R.ID.vIEwpager); vIEwpager.setAdapter(new SamplePagerAdapter()); } public class SamplePagerAdapter extends PagerAdapter { private final Random random = new Random(); private int mSize; public SamplePagerAdapter() { mSize = 5; } public SamplePagerAdapter(int count) { mSize = count; } @OverrIDe public int getCount() { return mSize; } @OverrIDe public boolean isVIEwFromObject(VIEw vIEw,Object object) { return vIEw == object; } @OverrIDe public voID destroyItem(VIEwGroup vIEw,int position,Object object) { vIEw.removeVIEw((VIEw) object); } @OverrIDe public Object instantiateItem(VIEwGroup vIEw,int position) { TextVIEw textVIEw = new TextVIEw(vIEw.getContext()); textVIEw.setText(position + 1 + ""); textVIEw.setBackgroundcolor(0xff000000 | random.nextInt(0x00ffffff)); textVIEw.setGravity(Gravity.CENTER); textVIEw.setTextcolor(color.WHITE); textVIEw.setTextSize(50); vIEw.addVIEw(textVIEw,VIEwGroup.LayoutParams.MATCH_PARENT,VIEwGroup.LayoutParams.MATCH_PARENT); return textVIEw; } // 增加item public voID addItem() { mSize++; notifyDataSetChanged(); } // 删除item public voID removeItem() { mSize--; mSize = mSize < 0 ? 0 : mSize; notifyDataSetChanged(); } }}
MainActivity.java需要的布局文件activity_main.xml:
<relativeLayout xmlns:androID="http://schemas.androID.com/apk/res/androID" xmlns:tools="http://schemas.androID.com/tools" androID:layout_wIDth="match_parent" androID:layout_height="match_parent" tools:context="zhangphil.demo.MainActivity" > <zhangphil.demo.LoopVIEwPager androID:ID="@+ID/vIEwpager" androID:layout_wIDth="match_parent" androID:layout_height="match_parent"/></relativeLayout>
核心关键代码LoopVIEwPager.java类和LoopVIEwPager.java依赖的LoopPagerAdapterWrapper.java!
LoopVIEwPager.java:
package zhangphil.demo;import androID.content.Context;import androID.support.v4.vIEw.PagerAdapter;import androID.support.v4.vIEw.VIEwPager;import androID.util.AttributeSet;import java.util.ArrayList;import java.util.List;public class LoopVIEwPager extends VIEwPager { private static final boolean DEFAulT_BOUNDARY_CASHING = false; private static final boolean DEFAulT_BOUNDARY_LOOPing = true; private LoopPagerAdapterWrapper mAdapter; private boolean mBoundaryCaching = DEFAulT_BOUNDARY_CASHING; private boolean mBoundaryLooPing = DEFAulT_BOUNDARY_LOOPing; private List<OnPagechangelistener> mOnPagechangelisteners; /** * helper function which may be used when implementing FragmentPagerAdapter * * @return (position-1)%count */ public static int toRealposition(int position,int count) { position = position - 1; if (position < 0) { position += count; } else { position = position % count; } return position; } /** * If set to true,the boundary vIEws (i.e. first and last) will never be * destroyed This may help to prevent "blinking" of some vIEws */ public voID setBoundaryCaching(boolean flag) { mBoundaryCaching = flag; if (mAdapter != null) { mAdapter.setBoundaryCaching(flag); } } public voID setBoundaryLooPing(boolean flag) { mBoundaryLooPing = flag; if (mAdapter != null) { mAdapter.setBoundaryLooPing(flag); } } @OverrIDe public voID setAdapter(PagerAdapter adapter) { mAdapter = new LoopPagerAdapterWrapper(adapter); mAdapter.setBoundaryCaching(mBoundaryCaching); mAdapter.setBoundaryLooPing(mBoundaryLooPing); super.setAdapter(mAdapter); setCurrentItem(0,false); } @OverrIDe public PagerAdapter getAdapter() { return mAdapter != null ? mAdapter.getRealAdapter() : mAdapter; } @OverrIDe public int getCurrentItem() { return mAdapter != null ? mAdapter.toRealposition(super.getCurrentItem()) : 0; } public voID setCurrentItem(int item,boolean smoothScroll) { int realitem = mAdapter.toInnerposition(item); super.setCurrentItem(realitem,smoothScroll); } @OverrIDe public voID setCurrentItem(int item) { if (getCurrentItem() != item) { setCurrentItem(item,true); } } @OverrIDe public voID setonPagechangelistener(OnPagechangelistener Listener) { addOnPagechangelistener(Listener); } @OverrIDe public voID addOnPagechangelistener(OnPagechangelistener Listener) { if (mOnPagechangelisteners == null) { mOnPagechangelisteners = new ArrayList<>(); } mOnPagechangelisteners.add(Listener); } @OverrIDe public voID removeOnPagechangelistener(OnPagechangelistener Listener) { if (mOnPagechangelisteners != null) { mOnPagechangelisteners.remove(Listener); } } @OverrIDe public voID clearOnPagechangelisteners() { if (mOnPagechangelisteners != null) { mOnPagechangelisteners.clear(); } } public LoopVIEwPager(Context context) { super(context); init(context); } public LoopVIEwPager(Context context,AttributeSet attrs) { super(context,attrs); init(context); } private voID init(Context context) { if (onPagechangelistener != null) { super.removeOnPagechangelistener(onPagechangelistener); } super.addOnPagechangelistener(onPagechangelistener); } private OnPagechangelistener onPagechangelistener = new OnPagechangelistener() { private float mPrevIoUsOffset = -1; private float mPrevIoUsposition = -1; @OverrIDe public voID onPageSelected(int position) { int realposition = mAdapter.toRealposition(position); if (mPrevIoUsposition != realposition) { mPrevIoUsposition = realposition; if (mOnPagechangelisteners != null) { for (int i = 0; i < mOnPagechangelisteners.size(); i++) { OnPagechangelistener Listener = mOnPagechangelisteners.get(i); if (Listener != null) { Listener.onPageSelected(realposition); } } } } } @OverrIDe public voID onPageScrolled(int position,float positionOffset,int positionOffsetPixels) { int realposition = position; if (mAdapter != null) { realposition = mAdapter.toRealposition(position); if (positionOffset == 0 && mPrevIoUsOffset == 0 && (position == 0 || position == mAdapter.getCount() - 1)) { setCurrentItem(realposition,false); } } mPrevIoUsOffset = positionOffset; if (mOnPagechangelisteners != null) { for (int i = 0; i < mOnPagechangelisteners.size(); i++) { OnPagechangelistener Listener = mOnPagechangelisteners.get(i); if (Listener != null) { if (realposition != mAdapter.getRealCount() - 1) { Listener.onPageScrolled(realposition,positionOffset,positionOffsetPixels); } else { if (positionOffset > .5) { Listener.onPageScrolled(0,0); } else { Listener.onPageScrolled(realposition,0); } } } } } } @OverrIDe public voID onPageScrollStateChanged(int state) { if (mAdapter != null) { int position = LoopVIEwPager.super.getCurrentItem(); int realposition = mAdapter.toRealposition(position); if (state == VIEwPager.SCRolL_STATE_IDLE && (position == 0 || position == mAdapter.getCount() - 1)) { setCurrentItem(realposition,false); } } if (mOnPagechangelisteners != null) { for (int i = 0; i < mOnPagechangelisteners.size(); i++) { OnPagechangelistener Listener = mOnPagechangelisteners.get(i); if (Listener != null) { Listener.onPageScrollStateChanged(state); } } } } };}
LoopPagerAdapterWrapper.java:
package zhangphil.demo;import androID.os.Parcelable;import androID.support.v4.app.FragmentPagerAdapter;import androID.support.v4.app.FragmentStatePagerAdapter;import androID.support.v4.vIEw.PagerAdapter;import androID.util.SparseArray;import androID.vIEw.VIEw;import androID.vIEw.VIEwGroup;public class LoopPagerAdapterWrapper extends PagerAdapter { private PagerAdapter mAdapter; private SparseArray<ToDestroy> mToDestroy = new SparseArray<>(); private static final boolean DEFAulT_BOUNDARY_CASHING = true; private static final boolean DEFAulT_BOUNDARY_LOOPing = true; private boolean mBoundaryCaching = DEFAulT_BOUNDARY_CASHING; private boolean mBoundaryLooPing = DEFAulT_BOUNDARY_LOOPing; voID setBoundaryCaching(boolean flag) { mBoundaryCaching = flag; } voID setBoundaryLooPing(boolean flag) { mBoundaryLooPing = flag; } LoopPagerAdapterWrapper(PagerAdapter adapter) { this.mAdapter = adapter; } @OverrIDe public voID notifyDataSetChanged() { mToDestroy = new SparseArray<>(); super.notifyDataSetChanged(); } int toRealposition(int position) { int realposition = position; int realCount = getRealCount(); if (realCount == 0) return 0; if (mBoundaryLooPing) { realposition = (position - 1) % realCount; if (realposition < 0) realposition += realCount; } return realposition; } public int toInnerposition(int realposition) { int position = (realposition + 1); return mBoundaryLooPing ? position : realposition; } private int getRealFirstposition() { return mBoundaryLooPing ? 1 : 0; } private int getRealLastposition() { return getRealFirstposition() + getRealCount() - 1; } @OverrIDe public int getCount() { int count = getRealCount(); return mBoundaryLooPing ? count + 2 : count; } public int getRealCount() { return mAdapter.getCount(); } public PagerAdapter getRealAdapter() { return mAdapter; } @OverrIDe public Object instantiateItem(VIEwGroup container,int position) { int realposition = (mAdapter instanceof FragmentPagerAdapter || mAdapter instanceof FragmentStatePagerAdapter) ? position : toRealposition(position); if (mBoundaryCaching) { ToDestroy toDestroy = mToDestroy.get(position); if (toDestroy != null) { mToDestroy.remove(position); return toDestroy.object; } } return mAdapter.instantiateItem(container,realposition); } @OverrIDe public voID destroyItem(VIEwGroup container,Object object) { int realFirst = getRealFirstposition(); int realLast = getRealLastposition(); int realposition = (mAdapter instanceof FragmentPagerAdapter || mAdapter instanceof FragmentStatePagerAdapter) ? position : toRealposition(position); if (mBoundaryCaching && (position == realFirst || position == realLast)) { mToDestroy.put(position,new ToDestroy(container,realposition,object)); } else { mAdapter.destroyItem(container,object); } } /* * Delegate rest of methods directly to the inner adapter. */ @OverrIDe public voID finishUpdate(VIEwGroup container) { mAdapter.finishUpdate(container); } @OverrIDe public boolean isVIEwFromObject(VIEw vIEw,Object object) { return mAdapter.isVIEwFromObject(vIEw,object); } @OverrIDe public voID restoreState(Parcelable bundle,ClassLoader classLoader) { mAdapter.restoreState(bundle,classLoader); } @OverrIDe public Parcelable saveState() { return mAdapter.saveState(); } @OverrIDe public voID startUpdate(VIEwGroup container) { mAdapter.startUpdate(container); } @OverrIDe public voID setPrimaryItem(VIEwGroup container,Object object) { mAdapter.setPrimaryItem(container,position,object); } /* * End delegation */ /** * Container class for caching the boundary vIEws */ static class ToDestroy { VIEwGroup container; int position; Object object; public ToDestroy(VIEwGroup container,Object object) { this.container = container; this.position = position; this.object = object; } }}
如果读者有兴趣使用,直接将上面两个核心关键代码放入到自己的项目代码包中,当作自己写的类直接使用即可,写布局时候不要再写VIEwPager,而是直接像我上面写的那个布局文件一样用LoopVIEwPager。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程小技巧。
总结以上是内存溢出为你收集整理的Android ViewPager实现智能无限循环滚动回绕效果全部内容,希望文章能够帮你解决Android ViewPager实现智能无限循环滚动回绕效果所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)