炫酷的ViewPager动画效果
2016-11-14 11:44 阅读(209)

ViewPager网上的例子很多,广告栏无限循环的例子也很多,优秀的开源项目更多,为什么我还要自己写呢?有个博主曾经说过,我觉得说得很好。他说,现在很多的开源库适用性比较广,我们如果去使用它,你会发现,很多功能我们是用不到的,而且会让程序包增大。更何况,不是自己写的代码,维护起来也是十分困难,万一哪天老板让你改一下里面的东西,你就懵逼了。所以我们有必要自己去造轮子,功能简单点没关系,一步步来嘛,时间一长,搞不好就是开源库了!

还是老规矩,在正文开始之前,先给大家看一下效果图


效果预览

整个ViewPager还是使用的上一篇文章的案例,唯一不同的就是,现在的这个ViewPager是它自己滚动的,我并没有用手指去拖动它。细心的人可能还会发现,每个视图切换的时候有个动画特效,这个也是我加上去的。
那么,我们今天的重点就是如何让ViewPager自动滚动,并且在滚动的时候加一点动画特效。

Tips:如果你是个热血青年,想亲自感受下这个控件的使用效果,那你可以扫描下方二维码,直接把Demo下载到手机上并安装。里面还包含了我之前写的很多案例,而且我会一直更新下去。放心下载吧,都是技术干货!


上面扯了一大堆废话,下面开始正式教学了。
首先,我们要处理自动滚动的问题。思路很简单,我们需要一个定时器,每隔一段时间就去切换一下ViewPager的视图。具体涉及到的工具类有Timer,TimerTask,Hander,这些都是干嘛用的,我来简单解释下。
Timer:定时器类
TimerTask:定时任务类,一般情况下和Timer搭配使用
Handler:在子线程中更新主线程UI
我之前是用Thread+Handler来实现的,你们千万不要这么做,会显得很傻。Android官方给我们提供了现成的定时器类,我们就没必要自己去用Thread实现了。
看一下代码吧:

//页面展示时间
private static final int DISPLAY_TIME = 3000;
private Handler hander = new Handler();
private Timer timer = new Timer();
private TimerTask timerTask;
private Runnable runable = new Runnable() {
    @Override
    public void run() {
        //true表示平滑滚动
        mViewPager.setCurrentItem(mViewPager.getCurrentItem() + 1, true);
    }
};
public void startScroll() {
    timerTask = new TimerTask() {
        @Override
        public void run() {
            hander.post(runable);
        }
    };
    timer.schedule(timerTask, DISPLAY_TIME, DISPLAY_TIME);
}
public void stopScroll() {
    timerTask.cancel();
    timerTask = null;
}

Runnable里面就一句话,目的是切换ViewPager到下一个视图。
startScroll( )方法就是很简单的timer和timertask的使用,整个方法的用途是:每三秒切换一次ViewPager页面
stopScroll( )方法就是将定时任务取消,也很简单。
以上的代码看不太懂的同学,一定要去学一下Timer,TimerTask,Handler的使用,因为网上有很多优秀的教程了,所以我就不想解释这三个类了,我肯定讲的没别人好。

这个时候,你只要调用startScroll( ),整个ViewPager就会开始滚动了。建议大家运行一下,第一部分就介绍到这里。看不太懂的同学不要往下看了,先把上面的弄懂再说,第二部分有更难的东西等着你去学习。


接下来我要介绍如何添加ViewPager的页面切换动画。
通过ViewPager.setPageTransformer(false, new MyPageTransformer( ));这个方法可以实现切换动画。可以这么说,通过这个方法,可以设置成任何你想要的动画。重点看MyPageTransformer是怎么写的,来,看一下代码:

/**
 * 页面切换时的动画
 * <p>
 * #{ViewPagerTransforms}项目为我们提供了一些现成的PageTransformer来实现一些动画
 *
 * @link git地址:https://github.com/ToxicBakery/ViewPagerTransforms
 */
private class MyPageTransformer implements ViewPager.PageTransformer {
    @Override
    public void transformPage(View page, float position) {
        if (position < -1) {
            page.setAlpha(0);
        } else if (position <= 0) {
            //ViewPager正在滑动时,页面左边的View       -1~0
            page.setAlpha(1);
            page.setTranslationX(0);
            page.setScaleX(1);
            page.setScaleY(1);
        } else if (position <= 1) {
            //ViewPager正在滑动时,页面右边的View       0~1
            page.setAlpha(1 - position);
            page.setTranslationX(0);
            page.setScaleX((float) (1 - position * 0.8));
            page.setScaleY((float) (1 - position * 0.8));
        } else {
            page.setAlpha(0);
        }
    }
}

这个类不是官方的,是我自己写的。首先,我这个类实现了ViewPager.PageTransformer接口,然后里面只有一个方法需要我去Override。transformPage这个方法还是挺复杂的,我这里不做介绍,大家可以去看一下网上的大神是如何介绍这个接口的,我也是现学现卖,就不装B了。当然,懒的同学可以去GitHub搜索ViewPagerTransforms,整个项目为我们提供了一些现成的PageTransformer来实现一些动画,地址:https://github.com/ToxicBakery/ViewPagerTransforms

到这一步,我们整个动画效果就做好了,运行一下代码,你会发现,动画效果闪的太快了,根本就看不清,除非我们手动去切换ViewPager界面,才能看清楚动画。针对这种情况,还是有解决方案的。

我就在想,到底是哪一个变量可以控制ViewPager的页面切换时间呢,于是我去看了ViewPager的源码,很快便找到了答案。ViewPager中的滑动控制器是Scroller,我们看到的滑动效果都是这个类来控制的。这时候思路就很简单了,我们直接去修改掉ViewPager中的Scroller就好了。这时候我很机智的想到了Java反射机制,可以动态修改类文件,于是就有了下面的代码

//页面切换时间
private static final int SCROLL_DURATION = 800;

/**
 * 利用反射原理来改变ViewPager页面切换时间
 */
private void setDefaultDuration() {
    try {
        Field field = ViewPager.class.getDeclaredField("mScroller");
        field.setAccessible(true);
        Scroller scroller = new Scroller(getContext(), new LinearInterpolator()) {
            @Override
            public void startScroll(int startX, int startY, int dx, int dy, int duration) {
                super.startScroll(startX, startY, dx, dy, SCROLL_DURATION);
            }
            @Override
            public void startScroll(int startX, int startY, int dx, int dy) {
                super.startScroll(startX, startY, dx, dy, SCROLL_DURATION);
            }
        };
        field.set(mViewPager, scroller);
    } catch (NoSuchFieldException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }
}

反射机制是Java基础,不是Android基础。看不懂的同学请花点时间去自学“java反射机制"。总而言之一句话,上面的代码就是把ViewPager中的scroller换成了我们自己的scroller,而我们自己的scroller又重新设置了滑动时间,ViewPager默认的滑动时间是250,我这里改成了800,时间太长了也不好,影响用户体验。

所有的工作都结束了,我们就应该来使用一下这个控件。使用超简单,跟上一篇文章没有太大区别,就是多了一行banner.startScroll()代码而已

@Override
public void initView(View view, @Nullable Bundle savedInstanceState) {
    banner = (Banner) view.findViewById(R.id.fragment_viewpager_imagebanner);
    banner.addContent(getImageView(R.drawable.mv1));
    banner.addContent(getImageView(R.drawable.mv2));
    banner.addContent(getImageView(R.drawable.mv3));
    banner.addContent(getImageView(R.drawable.mv4));
    banner.startScroll();
}
private ImageView getImageView(int resId) {
    ImageView image = new ImageView(context);
    image.setImageResource(resId);
    return image;
}

最后一步,运行程序。(我这里就不运行了)都封装好了,所以使用起来特别简单,充分体现出了“封装”的重要性。

大功告成!!!
我总结一下,这里面用到了Timer,TimerTask,Handler,ViewPager.PageTransformer,反射。
有的同学看完了我的文章,觉得什么都没学会。我这么说吧,以前我自学Android的时候,想在短时间内提升自己,但是不知道去学什么。我更不知道哪些知识点是常用的,哪些知识点是不常用的,然后就一头乱撞,撞到哪就算哪,学了很久,发现什么都没学会,我甚至都想去培训机构培训了。某些我认为很重要的东西,在公司的实际项目中却很少用到,浪费了大量的时间。于是我就去知乎,百度,谷歌,各种技术论坛里面搜,哪些知识点是公司里面经常用到的,搜出来一大堆,等我学完了,我发现我还是什么都不会,因为我做不出案例来。现在我通过案例来自我提升,然后又通过案例告诉你们哪些东西是重要的,你们就可以顺藤摸瓜,去学习新的知识,最后一定会收获很多的。不要总是抱怨没有人带你,没有人带你你就不会自学吗?我已经给你们指引正确的方向了,比我当时自己乱撞好很多了。
最后,不懂的人可以留言,我会尽量给你解答。希望大家可以亲自去实践一下,把代码写出来,然后简单分析一下原因。实在懒的人可以去我的Github上拷贝一下代码,这篇博客的代码不是很完整,重点讲解思路,完整的代码在这里:https://github.com/Elder-Wu/Notes