昊鑫隆百货,中信金通太阳网,海怡大桥
android系统提供的viewpager标准方式是左右可以自由滑动,但是滑动到最左边的极限位置是第一个page,滑动到最右边的位置是最后一个page,当滑动到最左或者最右时候,就不能再滑动/滚动了,这是android系统默认的viewpager实现方式。
但是有些情况下开发者可能希望viewpager能够智能的无限循环滚动回绕,比如现在总共有编号1, 2, 3, 4, 5的5个page。
(1)当用户手指从右往左滚动到最右边/最后面的页面5时候,如果此时用户继续拖住viewpager往左边滑动,那么viewpager将回绕、循环到第一个page -> 1,接着就是2,3,4,5;
(2)反过来,如果当用户手指从左往右,滑到最左边的第一个page:1时候,如果此时继续拖住viewpager继续从左往右滑动,那么将回绕到5,接着就是4,3,2,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, 0); } else { listener.onpagescrolled(realposition, 0, 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, int position, 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, realposition, 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, int position, 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, int position, object object) { this.container = container; this.position = position; this.object = object; } } }
如果读者有兴趣使用,直接将上面两个核心关键代码放入到自己的项目代码包中,当作自己写的类直接使用即可,写布局时候不要再写viewpager,而是直接像我上面写的那个布局文件一样用loopviewpager。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。
如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复
Android studio 解决logcat无过滤工具栏的操作
Android Studio 恢复小窗口停靠模式(Docked Mode)
Android studio保存logcat日志到本地的操作
Android Studio快捷键生成TAG、Log.x日志输出介绍
网友评论