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

来源:互联网 发布:阿里云esc远程连接 编辑:程序博客网 时间:2024/05/20 21:46

使用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的博文