ViewPager无限轮播与自定义切换动画
2017-01-05 21:10 阅读(240)

一直在寻求一个能用得长久的ViewPager,寻寻觅觅终于发现,ViewPager有这一个就够了。

注:并非完全原创

先看一下效果:

淡入淡出:

view_pager_alpha

旋转:

view_pager_rotate

无限轮播的ViewPager

主要设计思路(以ViewPager右滑为例):

/**
 * 自动轮播的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。

淡入淡出的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);
        }

    }
}


作者:疯狂的妞妞