使用ViewPager实现幻灯片播放功能

使用Viewpager实现幻灯片播放功能

最近要由于项目需要,要实现一个支持幻灯片播放功能的
图片轮播功能,自己在实现过程中也做了些总结,现在记录下来,以便之后复看,也希望可以帮到一些需要帮助的人吧。

基本的思路

总的来说实现幻灯片播放的思路如下:
- 1 完成动画效果
- 2 完成定时切换


1.动画切换效果

原理解析

完成动画切换效果的方法是通过ViewPager的这个函数实现:ViewPager.setPageTransformer(boolean reverseDrawingOrder,ViewPager.PageTransformer transformer);
我们先来看看这个方法的一些介绍:


Sets a {@link PageTransformer} that will be called for each attached page whenever
* the scroll position is changed. This allows the application to apply custom property
* transformations to each page, overriding the default sliding behavior.


大体意思就是说当ViewPager滑动时,设置的PageTransformer中的对应方法会被调用,使得应用可以使用自己的方式来实现不同的页面切换效果
那么这个动画切换效果的具体实现该怎么写呢,我们来看看ViewPager
.PageTransformer接口定义的方法:

 public interface PageTransformer {
        /**
         * Apply a property transformation to the given page.
         *
         * @param page Apply the transformation to this page
         * @param position Position of page relative to the current front-and-center
         *                 position of the pager. 0 is front and center. 1 is one full
         *                 page position to the right, and -1 is one page position to the left.
         */
        void transformPage(View page, float position);
    }

简单来说,就是当一个页面完全处于中间时,position的大小为0,当页面从中间向左滑动直到刚好消失时,position的变化为0 ->-1,当页面从中间向右滑动到刚好消失时,position的变化为0 -> 1。这样子我们就可以通过position的变化,在不同的position时将当前的page设置不同的属性(例如setTranslation,setRotation,setAlpha等),达到各种各样的页面切换效果.


一些实现的效果:
  • 立方体旋转效果:

立方体旋转

@Override
    public void transformPage(View page, float position) {

        //终极无敌史诗级例外的操作 position < -1 || position > 1
        if ((position < -1) || (position > 1)){
            return;
        }
        //刚好不可见 复原
        if ((position == -1) ||(position == 1)){
            resetPage(page);
            return;
        }
        //从左边出去
        if (position <= 0) {

            page.setPivotX(page.getWidth());
            page.setPivotY(page.getHeight() * 0.5f);
            page.setRotationY(90f * position);
            return;
        }
        //从右边出去
        if (position < 1){

            page.setPivotX(0);
            page.setPivotY(page.getWidth() * 0.5f);
            page.setRotationY(90f * position);
            return;
        }

    }
    /**
     * 恢复page的属性
     * @param page 指定的view
     */
    void resetPage(View page){
        //设置旋转中心点;
        page.setPivotX(page.getWidth());
        page.setPivotY(page.getHeight() * 0.5f);
        //只在Y轴做旋转操作
        page.setRotationY(0);

    }

  • 中心旋转效果

中心旋转

@Override
    public void transformPage(View page, float position) {
        int pageWidth = page.getWidth();

        //终极无敌史诗级例外的操作 position < -1 || position > 1
        if ((position < -1) || (position > 1)){
            return;
        }
        //刚好不可见 复原
        if ((position == -1) || (position == 1)){
            resetPage(page);
            return;
        }
        //从左边出去
        if (position <= 0){
            //阻止消失界面的移动
            page.setTranslationX(-pageWidth * position);

            final float rotation = -180f * position;
            page.setPivotX(page.getWidth() * 0.5f);
            page.setPivotY(page.getHeight() * 0.5f);
            page.setRotation(rotation);

            float alphaFactor = Math.max(0.0f, 1 - Math.abs(position));
            //透明度改变
            page.setAlpha(alphaFactor);
            return;
        }
        //从右边出去
        if (position < 1){
            //阻止出现的界面的移动
            page.setTranslationX(-pageWidth * position);

            final float rotation = -180f * position;
            page.setPivotX(page.getWidth() * 0.5f);
            page.setPivotY(page.getHeight() * 0.5f);
            page.setRotation(rotation);

            float alphaFactor = Math.max(0.0f, 1 - Math.abs(position));
            //透明度改变
            page.setAlpha(alphaFactor);
            return;
        }

    }

    /**
     * 恢复page的属性
     * @param page 当前page
     */
    void resetPage(View page){
        page.setAlpha(1.0f);
        page.setTranslationX(0);
        page.setPivotX(0);
        page.setPivotY(0);
        page.setRotation(0.0f);
    }

  • 缩小平移效果
    缩小平移
    private static final float MIN_SCALE = 0.85f;
    private static final float MIN_ALPHA = 0.5f;

    @Override
    public void transformPage(View page, float position) {

        int pageWidth = page.getWidth();
        int pageHeight = page.getHeight();

        //终极无敌史诗级例外的操作 position < -1 || position > 1
        if ((position < -1) || (position > 1)){
            return;
        }
        //刚好不可见 复原
        if ((position == -1) || (position == 1)){
            resetPage(page);
            return;
        }
        //从左边出去
        if (position <= 0){
            float scaleFactor = Math.max(MIN_SCALE,1-Math.abs(position));
            float vertMargin = pageHeight * (1 - scaleFactor) / 2;
            float horMargin = pageWidth * (1 - scaleFactor) / 2;
            //左移
            page.setTranslationX(horMargin - vertMargin / 2);

            // Scale the page down (between MIN_SCALE and 1)
            page.setScaleX(scaleFactor);
            page.setScaleY(scaleFactor);

            // Fade the page relative to its size.
            page.setAlpha(MIN_ALPHA +
                    (scaleFactor - MIN_SCALE) /
                            (1 - MIN_SCALE) * (1 - MIN_ALPHA));
            return;
        }
        //从右边出去
        if (position < 1){
            float scaleFactor = Math.max(MIN_SCALE,1-Math.abs(position));
            float vertMargin = pageHeight * (1 - scaleFactor) / 2;
            float horMargin = pageWidth * (1 - scaleFactor) / 2;

            page.setTranslationX(-horMargin + vertMargin / 2);

            // Scale the page down (between MIN_SCALE and 1)
            page.setScaleX(scaleFactor);
            page.setScaleY(scaleFactor);

            // Fade the page relative to its size.
            page.setAlpha(MIN_ALPHA +
                    (scaleFactor - MIN_SCALE) /
                            (1 - MIN_SCALE) * (1 - MIN_ALPHA));
            return;

        }
    }
    /**
     * 恢复page的属性
     * @param page 当前page
     */
    void resetPage(View page){
        page.setAlpha(1.0f);
        page.setTranslationX(0.0f);
        page.setScaleX(1.0f);
        page.setScaleY(1.0f);
    }

  • 旋转向下
    旋转向下
@Override
    public void transformPage(View page, float position) {
        final float MAX_ROTATE_ANGLE = 20.0f;
        //终极无敌史诗级例外的操作 position < -1 || position > 1
        if ((position < -1) || (position > 1)){
            return;
        }
        //刚好不可见 复原
        if ((position == -1) || (position == 1)){
            resetPage(page);
            return;
        }
        //从左边出去
        if (position <= 0){
            float angle = MAX_ROTATE_ANGLE * position;
            page.setPivotX(page.getWidth() * 0.5f);
            page.setPivotY(page.getHeight());
            page.setRotation(angle);
            return;
        }
        //从右边出去
        if (position < 1){
            float angle = MAX_ROTATE_ANGLE * position;
            page.setPivotX(page.getWidth() * 0.5f);
            page.setPivotY(page.getHeight());
            page.setRotation(angle);
            return;
        }
    }
    /**
     * 恢复page的属性
     * @param page 当前page
     */
    void resetPage(View page){
        page.setPivotX(page.getWidth() * 0.5f);
        page.setPivotY(page.getHeight());
        page.setRotation(0);
    } 

  • 放大进入
    放大进入
@Override
    public void transformPage(View page, float position) {

        //终极无敌史诗级例外的操作 position < -1 || position > 1
        if ((position < -1) || (position > 1)){
            return;
        }
        //刚好不可见 复原
        if ((position == -1)){
            page.setPivotX(0);
            page.setPivotY(page.getHeight() * 0.5f);
            page.setScaleX(1.0f);
            page.setScaleY(1.0f);
            return;
        }
        //刚好不可见 复原
        if (position == 1){
            page.setPivotX(page.getWidth());
            page.setPivotY(page.getHeight() * 0.5f);
            page.setScaleX(1.0f);
            page.setScaleY(1.0f);
            return;
        }
        //从左边出去
        if (position <= 0){

            page.setPivotX(0);
            page.setPivotY(page.getHeight() * 0.5f);
            float scale = 1.0f + position;
            page.setScaleX(scale);
            page.setScaleY(scale);

            return;
        }
        //从右边出去
        if (position < 1){

            page.setPivotX(page.getWidth());
            page.setPivotY(page.getHeight() * 0.5f);
            float scale = 1.0f - position;
            page.setScaleX(scale);
            page.setScaleY(scale);

            return;
        }
    }

2.定时切换

这个实际上还蛮好实现的,我当时选择的实现方式是使用Timer + Handler的实现方式,主要是通过使用
Timer.scheduleAtFixedRate(TimerTask task, long delay, long period),通过设定period长短控制播放速度,在Timerask中发送message,通知Handler执行切换,完成幻灯片播放效果.


3.一些坑的地方

  • 1.幻灯片播放功能中有切换动画的设置功能,之前在实现的时候,在切换了动画之后,当前page前后的两个page都没有复原,导致切换效果很奇怪,后来就在page变为不可见之后,将其所有属性复原,即可。

  • 2.当进入到幻灯片播放模式之后,当前页面的切换动画总是一闪而过,导致切换效果很难受,所以查阅资料之后,发现可以通过修改ViewPager的mScroller的实现,来指定每一次scroll的时延。以下是解决方法:

/**
     * 使用反射设置viewpager的页面切换时间
     * @param scrollDuration 切换时长
     * @param isReset 是否恢复原来的效果 true:恢复 false:不恢复 一般为true
     */
    private void setScrollDuration(final int scrollDuration, final boolean isReset){
        LogUtils.d(TAG, "setScrollDuration: duration: " + scrollDuration);
        try {
            Field field = ViewPager.class.getDeclaredField("mScroller");
            field.setAccessible(true);

            Scroller mScroller = new Scroller(this,new LinearInterpolator()){
                @Override
                public void startScroll(int startX, int startY, int dx, int dy) {
                    if (isReset){
                        super.startScroll(startX, startY, dx, dy);
                    }else{
                        super.startScroll(startX, startY, dx, dy,scrollDuration);
                    }
                }

                @Override
                public void startScroll(int startX, int startY, int dx, int dy, int duration) {
                    if (isReset){//由系统控制
                        super.startScroll(startX, startY, dx, dy, duration);
                    }else{//幻灯片播放
                        super.startScroll(startX, startY, dx, dy, scrollDuration);
                    }
                }
            };
            field.set(mPictureViewPager,mScroller);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e){
            e.printStackTrace();
        }
    }

上面的实现都很清晰了,就不做介绍了。


好了,这篇文章就这么愉快地结束了

参考资料:

鸿洋大神的博文

suyan_why的博文

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值