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