一直在寻求一个能用得长久的ViewPager,寻寻觅觅终于发现,ViewPager有这一个就够了。
注:并非完全原创
先看一下效果:
淡入淡出:
旋转:
无限轮播的ViewPager
主要设计思路(以ViewPager右滑为例):
无限轮播:通过Handler负责View的切换,每次向自身发送延迟消息,达到无限循环的目的;当处于ViewPager最后一个时候,继续向右滑,调用setCurrentItem,回到第一个;。
自动切换动画的速度设置:通过Java反射机制获取父类的Scroller,在子类中创建我们自己的Scroller,通过Scroller设置切换动画的速度。
/** * 自动轮播的ViewPager * Created by ChenSS on 2017/1/5. */ public class MylViewPager extends ViewPager { public static final int DEFAULT_INTERVAL = 1500; public static final int LEFT = 0; public static final int RIGHT = 1; /** * 什么也不做,当滑动在最后一项或者第一项,什么也不做 **/ public static final int SLIDE_BORDER_MODE_NONE = 0; /** * 当滑动在最后一项或者第一项,开启循环,这种模式下,当滑到最后一个Item回到第一个Item, * 这种模式下,最后一个Item和第一个Item相同的话会显得自然一些 **/ public static final int SLIDE_BORDER_MODE_CYCLE = 1; /** * 当滑动在最后一项或者第一项,开启循环,并且阻止事件拦截 **/ public static final int SLIDE_BORDER_MODE_TO_PARENT = 2; /** * 自动滚动的时间,以毫秒为单位 **/ private long interval = DEFAULT_INTERVAL; /** * 自动滚动方向, default is {@link #RIGHT} **/ private int direction = RIGHT; /** * 是否自动循环 **/ private boolean isCycle = true; /** * 接触时是否停止自动滚动 **/ private boolean stopScrollWhenTouch = true; /** * 如何处理当滑动在最后还是第一项 **/ private int slideBorderMode = SLIDE_BORDER_MODE_NONE; /** * 动画时是否自动滚动在最后或第一项取消动画 **/ private boolean isBorderAnimation = false; private Handler handler; private boolean isAutoScroll = false; private boolean isStopByTouch = false; private float touchX = 0f, downX = 0f; private CustomDurationScroller scroller = null; public static final int SCROLL_WHAT = 0; public MylViewPager(Context paramContext) { super(paramContext); init(); } public MylViewPager(Context paramContext, AttributeSet paramAttributeSet) { super(paramContext, paramAttributeSet); init(); } private void init() { handler = new MyHandler(); setViewPagerScroller(); } public void setSlideBorderMode(int slideBorderMode) { this.slideBorderMode = slideBorderMode; } public void setDirection(int direction) { this.direction = direction; } /** * 启动动画 */ public void startAutoScroll() { isAutoScroll = true; sendScrollMessage(interval); } /** * 启动动画 */ public void startAutoScroll(int delayTimeInMills) { isAutoScroll = true; sendScrollMessage(delayTimeInMills); } /** * 停止动画 */ public void stopAutoScroll() { isAutoScroll = false; handler.removeMessages(SCROLL_WHAT); } /** * 设置动画切换的时间 */ public void setScrollDurationFactor(double scrollFactor) { scroller.setScrollDurationFactor(scrollFactor); } private void sendScrollMessage(long delayTimeInMills) { handler.removeMessages(SCROLL_WHAT); handler.sendEmptyMessageDelayed(SCROLL_WHAT, delayTimeInMills); } /** * 利用反射机制修改滚动的时间 */ private void setViewPagerScroller() { try { Field scrollerField = ViewPager.class.getDeclaredField("mScroller"); scrollerField.setAccessible(true); //插值器 Field interpolatorField = ViewPager.class.getDeclaredField("sInterpolator"); interpolatorField.setAccessible(true); scroller = new CustomDurationScroller(getContext(), (Interpolator) interpolatorField.get(null)); scrollerField.set(this, scroller); } catch (Exception e) { e.printStackTrace(); } } /** * 选择滑动到哪一页 */ public void scrollOnce() { PagerAdapter adapter = getAdapter(); int currentItem = getCurrentItem(); int totalCount; if (adapter == null || (totalCount = adapter.getCount()) <= 1) { return; } int nextItem = (direction == LEFT) ? --currentItem : ++currentItem; if (nextItem < 0) { if (isCycle) { setCurrentItem(totalCount - 1, isBorderAnimation); //如果是第一个就0延迟 sendScrollMessage(0); } } else if (nextItem == totalCount) { if (isCycle) { setCurrentItem(0, isBorderAnimation); //如果是最后一个就0延迟 sendScrollMessage(0); } } else { //默认情况就按照设定的时间切换图片 setCurrentItem(nextItem, true); sendScrollMessage(interval); } } @Override public boolean onTouchEvent(MotionEvent ev) { if (stopScrollWhenTouch) { if (ev.getAction() == MotionEvent.ACTION_DOWN && isAutoScroll) { isStopByTouch = true; stopAutoScroll(); } else if (ev.getAction() == MotionEvent.ACTION_UP && isStopByTouch) { startAutoScroll(); } } if (slideBorderMode == SLIDE_BORDER_MODE_TO_PARENT || slideBorderMode == SLIDE_BORDER_MODE_CYCLE) { touchX = ev.getX(); if (ev.getAction() == MotionEvent.ACTION_DOWN) { downX = touchX; } int currentItem = getCurrentItem(); PagerAdapter adapter = getAdapter(); int pageCount = adapter == null ? 0 : adapter.getCount(); if ((currentItem == 0 && downX <= touchX) || (currentItem == pageCount - 1 && downX >= touchX)) { //事件拦截 if (slideBorderMode == SLIDE_BORDER_MODE_TO_PARENT) { getParent().requestDisallowInterceptTouchEvent(false); } else { if (pageCount > 1) { setCurrentItem(pageCount - currentItem - 1, isBorderAnimation); } getParent().requestDisallowInterceptTouchEvent(true); } return super.onTouchEvent(ev); } } getParent().requestDisallowInterceptTouchEvent(true); return super.onTouchEvent(ev); } private class MyHandler extends Handler { @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what) { case SCROLL_WHAT: scrollOnce(); //下面的方法,Handler向自身发送延迟消息 //sendScrollMessage(interval); default: break; } } } class CustomDurationScroller extends Scroller { private double scrollFactor = 1; public CustomDurationScroller(Context context, Interpolator interpolator) { super(context, interpolator); } /** * 设置滚动切换的时间 */ public void setScrollDurationFactor(double scrollFactor) { this.scrollFactor = scrollFactor; } @Override public void startScroll(int startX, int startY, int dx, int dy, int duration) { super.startScroll(startX, startY, dx, dy, (int) (duration * scrollFactor)); } } }
自定义ViewPager动画
首先你要实现ViewPager.PageTransformer接口,你需要设计transformPage(View view, float position)的方法体,第一个参数是具体的Item,第二个参数是Item的position,也就是Item的位置。
position是一个极为关键的参数, 当我们的View显示在屏幕上的时候,position的值是-1到1。
当position大于-1小于0时,表示View正在从左侧滑入(也可能滑出,如果ViewPager滑的方向换掉);
当等于0,表示View刚刚好显示在屏幕中,但是通常获取不到这个刚刚等零的值;
当position大于0小于1,表示View正在从右侧滑出(也可能滑入,如果ViewPager滑的方向换掉)。
淡入淡出的ViewPager切换动画
/** * ViewPager的滑动特效 * Created by ChenSS on 2017/1/5. */ public class AlphaPageTransformer implements ViewPager.PageTransformer { /** * 以阿尔法值为例,这个是0-1的值,可以设置View的透明度 */ private float alpha; /** * 在这里编辑你ViewPager的动画特效 * * @param view 拿到你ViewPager的Item的View * @param position View现在所处的位置 */ @Override public void transformPage(View view, float position) { if (position < -1) { //当它消失在左边,通常还原最普通的状态,设置Alpha为1 ViewHelper.setAlpha(view, 1); } else if (position <= 0) { //左滑特效,这个时候它的position在屏幕左侧,所以是负值 alpha = 1 - (0 - position); ViewHelper.setAlpha(view, alpha); } else if (position <= 1) { //右滑特效,这个时候它的position在屏幕上,所以是正值 alpha = 1 - position; ViewHelper.setAlpha(view, alpha); } else { //当它消失在右边,通常还原最普通的状态,设置Alpha为1 ViewHelper.setAlpha(view, 1); } } }
旋转的ViewPager切换动画
/** * 旋转 * Created by ChenSS on 2017/1/5. */ public class RotatePageTransformer implements ViewPager.PageTransformer { private static final float BASE_ANGLE = 10.0f; private float angle; public void transformPage(View view, float position) { if (position < -1) { ViewHelper.setRotation(view, 0); } else if (position <= 0) { angle = (BASE_ANGLE * position); ViewHelper.setPivotX(view, view.getMeasuredWidth() * 0.5f); ViewHelper.setPivotY(view, view.getMeasuredWidth() * 0.5f); ViewHelper.setRotation(view, angle); } else if (position <= 1) { angle = (BASE_ANGLE * position); ViewHelper.setPivotX(view, view.getMeasuredWidth() * 0.5f); ViewHelper.setPivotY(view, view.getMeasuredWidth() * 0.5f); ViewHelper.setRotation(view, angle); } else { ViewHelper.setRotation(view, 0); } } }
测试代码
代码我没全贴出来,Activity的布局文件只有ViewPager,然后Fragment的布局文件只有ImageView,比较简单。
public class MaterialDesignViewPagerActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_material_design_view_pager); MylViewPager viewPager = (MylViewPager) findViewById(R.id.md_view_pager_asvp); ArrayList<Fragment> fragmentList = new ArrayList<>(); //注意首尾的Item是一样的 fragmentList.add(new RecyclerViewBean(R.mipmap.b_1)); fragmentList.add(new RecyclerViewBean(R.mipmap.b_2)); fragmentList.add(new RecyclerViewBean(R.mipmap.b_3)); fragmentList.add(new RecyclerViewBean(R.mipmap.b_1)); RecyclerVpAdapter bAdapter = new RecyclerVpAdapter(getSupportFragmentManager(), fragmentList); viewPager.setAdapter(bAdapter); viewPager.setCurrentItem(0); //自动滑动方向往左 viewPager.setDirection(MylViewPager.LEFT); //开启无限循环的MODE viewPager.setSlideBorderMode(MylViewPager.SLIDE_BORDER_MODE_CYCLE); //设置自定义Alpha切换动画效果 viewPager.setPageTransformer(true, new AlphaPageTransformer()); //设置动画切换的速度 viewPager.setScrollDurationFactor(10); //开启自动轮播,设置每次切换的时间间隔 viewPager.startAutoScroll(2000); } class RecyclerVpAdapter extends FragmentPagerAdapter { ArrayList<Fragment> list; public RecyclerVpAdapter(FragmentManager fragmentManager, ArrayList<Fragment> list) { super(fragmentManager); this.list = list; } @Override public int getCount() { return list.size(); } @Override public Fragment getItem(int arg0) { return list.get(arg0); } } }
作者:疯狂的妞妞