咱們以知乎日報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的默認行爲就好,要注意增長任何功能都要考慮應用場景,避免多此一舉。