咱们以知乎日报Android客户端的轮播控件为例,分析一下轮播控件的主要组成:android
首先咱们要有用来显示图片的View对象,根据上图中底部中央的5个点,咱们知道须要5个ImageView来显示须要轮播的图片,另外还须要5个ImageView来显示5个点。如今考虑如下轮播组件应该具备的行为,首先须要每隔必定时间间隔切换到下一张图片,而且图片间切换的效果应该是平滑的,就像“翻书”同样。由此咱们能够想到将5个图片当作ViewPager的Page,这样图片切换时天然会有平滑的效果。接下来,咱们还要给底部的5个小点找一个父容器,因为它们是线性排列的,因此用LinearLayout是再合适不过了。而后,咱们还要把ViewPager和容纳5个点的LinearLayout放入一个父容器中,这里咱们选择使用垂直排列子View的LinearLayout。git
这样一来,咱们就获得了轮播控件的布局文件(carousel_layout.xml):github
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <android.support.v4.view.ViewPager android:id="@+id/view_pager" android:layout_width="match_parent" android:layout_height="match_parent" /> <LinearLayout android:id="@+id/dots" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" android:gravity="center" android:orientation="horizontal" android:padding="8dp" > </LinearLayout> </LinearLayout>
经过对轮播控件的组成部分进行分析,咱们已经肯定了轮播控件的用户界面,那么接下来,咱们要作的就是实现轮播控件的”算法“,也就是业务逻辑。算法
轮播控件首先要具备的行为是自动播放,也就是每隔必定时间间隔(一般是3到5秒),便自动”翻到下一页“。为了实现这一点,咱们能够维护一个currentItem变量来记录当前正在显示的图片,而后设置一个定时任务,调用ViewPager的setCurrentItem方法设置当前要显示的图片,并将currentItem设为下一张要显示的图片。有一点须要咱们注意的即是播放到最后一张图片时,下一个被显示的应该是第一个图片,并且切换的效果也再也不是平滑的。ide
轮播控件的还要能响应咱们的滑动动做,也就是咱们可以经过左右滑动来在不一样的图片之间切换,这个行为ViewPager自动为咱们提供了。另外还有一个轮播控件应该具有的行为是:当切换到指定图片时,相应的圆点应该以区别其余4个圆点的颜色显示,以便用户可以知道当前正在播放的是第几个图片。要实现这一点也不复杂,只须要为ViewPager添加一个OnPageChangeListener监听器,而后重写相应的回调方法便可,这样当用户选定了某个Page时,onPageSelected方法会被回调,系统会传入当前Page的索引,咱们即可以根据这个索引设置相应的圆点颜色。布局
通过以上的分析,咱们已经清楚的了解了轮播组件的表示及业务逻辑,接下来只要咱们用Java把这些描述出来就大功告成了。post
咱们须要定时执行“改变ViewPager当前Page为下一个Page”这一任务,这里咱们采用Handler来实现,代码以下:spa
1 mHandler.postDelayed(task, DELAY); 2 private final Runnable task = new Runnable() { 3 @Override 4 public void run() { 5 if (isAutoPlay) { 6 currentItem = (currentItem + 1) % (mTopStories.size()); 7 mVP.setCurrentItem(currentItem); 8 mHandler.postDelayed(task, DELAY); 9 } else { 10 mHandler.postDelayed(task, DELAY); 11 } 12 } 13 };
在以上代码中,DELAY表明咱们设置的一个延迟常量(单位ms)。因为咱们须要的是循环播放,所以第5张显示完毕后应该显示第一张,因此咱们要想第6行那样进行一个模运算,这样currentItem就在0到4之间不停变化了。注意第5行有一个isAutoPlay变量,这个变量表示当前是否应该自动播放。那么何时不该该自动播放呢?咱们知道当咱们滑动手指切换图片时,图片会“跟随”着咱们的手,就比如咱们翻书页的时候,只有松开了手书页才能落下。因此咱们正在“拖动”图片时,也就是咱们的手还没松开时,轮播控件是不该该自动播放的。为了实现这一点,咱们只需重写OnPageChangeListener中的onPageScrollStateChanged方法,在当前状态为“拖动”时设置isAutoPlay变量为false。从第10行咱们能够知道,当autoPlay为false时,不会改变当前显示的图片,仅仅会等过了DELAY指定的时间后再执行下一次定时任务。code
上面咱们提到了要给ViewPager添加一个OnPageChangeListener监听器对象,来实现小圆点颜色的改变以及autoPlay变量的赋值。具体的实现请看如下代码,代码的含义都很直接:xml
1 class TopOnPageChangeListener implements ViewPager.OnPageChangeListener { 2 3 @Override 4 public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { 5 6 } 7 8 @Override 9 public void onPageSelected(int position) { 10 for (int i = 0; i < mDotsIV.size(); i++) { 11 if (i == position) { 12 mDotsIV.get(i).setImageResource(R.drawable.dot_focus); 13 } else { 14 mDotsIV.get(i).setImageResource(R.drawable.dot_blur); 15 } 16 } 17 } 18 19 @Override 20 public void onPageScrollStateChanged(int state) { 21 switch (state) { 22 //SCROLL_STATE_DRAGGING 23 case 1: 24 isAutoPlay = false; 25 break; 26 //SCROLL_STATE_SETTLING 27 case 2: 28 isAutoPlay = true; 29 break; 30 default: 31 break; 32 } 33 } 34 }
在以上代码的第10到16行,咱们重写了onPageSelected方法,position参数表示当前Page的索引。这个方法中,咱们设置当前图片对应的圆点图片为dot_focus,设置其余圆点的图片为dot_blur,这样用户就能知道当前的位置。在第21行到32行,咱们重写了onPageScrollStateChanged方法,state参数表明了当前的“滚动状态,这个值为1表示当前用户正在”拖动“的过程当中,所以要设置isAutoPlay为false;这个值为2表示用户松开了手,图片正在”滚动“中,这时咱们就要把isAutoPlay设回默认值true,恢复自动播放。
有时候咱们但愿可以从最后一页直接“翻到”第一页,而这种行为默认不被PagerView所支持,要想实现这个行为,咱们能够在PagerView中增长一些“辅助页”,并重写OnPageChangeLisener中的相关方法。然而咱们在不少场景中只须要保持PagerView的默认行为就好,要注意增长任何功能都要考虑应用场景,避免多此一举。