欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android實(shí)現(xiàn)帶指示器的自動(dòng)輪播式ViewPager

 更新時(shí)間:2017年02月16日 11:02:42   作者:程序員的自我反思  
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)帶指示器的自動(dòng)輪播式ViewPager的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

前言

最近在做項(xiàng)目的時(shí)候,有個(gè)需求就是實(shí)現(xiàn)自動(dòng)輪播式的ViewPager,最直觀的例子就是知乎日?qǐng)?bào)頂部的ViewPager,它內(nèi)部有著好幾個(gè)子view,每個(gè)一段時(shí)間便自動(dòng)滑動(dòng)到下一個(gè)item view,而底部的指示器也隨之跟著改變。使用這種ViewPager的好處是在有限的空間內(nèi)可以展示出多樣化的信息。輪播式ViewPager廣泛應(yīng)用于各種應(yīng)用內(nèi)部,用于展示廣告等。抱著學(xué)習(xí)和分享的目的,筆者把輪播式ViewPager寫(xiě)成了一個(gè)獨(dú)立的控件,以方便以后的使用。

效果展示

話不多說(shuō),我們先來(lái)看看實(shí)現(xiàn)的效果是怎樣的:

手指觸摸滑動(dòng)

從上面的動(dòng)態(tài)圖可以看到,當(dāng)我們手指拖動(dòng)ViewPager的時(shí)候,下方的指示器隨著頁(yè)面的滑動(dòng)而滑動(dòng),當(dāng)點(diǎn)擊添加數(shù)據(jù)的按鈕的時(shí)候,ViewPager的數(shù)據(jù)項(xiàng)變多,同時(shí)下方的指示器也隨之改變,適應(yīng)了數(shù)據(jù)項(xiàng)的數(shù)目。

自動(dòng)滑動(dòng)

從上面的動(dòng)態(tài)圖可以看到,當(dāng)我們不用手指進(jìn)行拖動(dòng)的時(shí)候,該ViewPager會(huì)每隔4s左右的時(shí)間自動(dòng)進(jìn)行滾動(dòng),滾動(dòng)到最后一個(gè)item view的時(shí)候,下一次會(huì)滾到第一個(gè)位置。

GitHub地址及使用介紹

讀者可以直接到我的GitHub中獲取源碼。
GitHub:BannerViewPager,控件及其相關(guān)文件都放在了該目錄下的library模塊內(nèi),而app模塊則是上面效果展示的一個(gè)簡(jiǎn)單應(yīng)用。

通過(guò)以下幾個(gè)步驟,就能方便地使用該控件了:
1、像普通的ViewPager一樣,在布局文件中放入該控件如下:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:orientation="vertical">

 <com.chenyu.library.bannerViewPager.BannerViewPager
 android:id="@+id/banner"
 android:layout_width="match_parent"
 android:layout_height="200dp">

 </com.chenyu.library.bannerViewPager.BannerViewPager>

 <!-- others -->
</LinearLayout>

2、獲取BannerViewPager的實(shí)例,進(jìn)行相應(yīng)的配置,比如我們使用ViewPager的時(shí)候,也需要設(shè)置它的適配器等。這里筆者實(shí)現(xiàn)了一個(gè)ViewPagerAdapter,用作BannerViewPager的適配器:

//獲取BannerViewPager實(shí)例
bannerViewPager = (BannerViewPager) findViewById(R.id.banner);
//實(shí)例化ViewPagerAdapter,第一個(gè)參數(shù)是View集合,第二個(gè)參數(shù)是頁(yè)面點(diǎn)擊監(jiān)聽(tīng)器
mAdapter = new ViewPagerAdapter(mViews, new OnPageClickListener() {
 @Override
 public void onPageClick(View view, int position) {
 Log.d("cylog","position:"+position);
 }
});
//設(shè)置適配器
bannerViewPager.setAdapter(mAdapter);

和一般的ViewPager沒(méi)什么兩樣,都是:獲取實(shí)例——?jiǎng)?chuàng)建適配器——設(shè)置適配器。而適配器的數(shù)據(jù)集一般都是一個(gè)View集合,用作ViewPager的item view,所以需要事先準(zhǔn)備好相應(yīng)的View集合。此外,一般輪播式ViewPager點(diǎn)擊某一項(xiàng)后會(huì)打開(kāi)相應(yīng)的頁(yè)面,所以這里提供了一個(gè)OnPageClickListener的監(jiān)聽(tīng)器,在創(chuàng)建適配器的時(shí)候同時(shí)創(chuàng)建該監(jiān)聽(tīng)器即可。

原理簡(jiǎn)析

接下來(lái),筆者將簡(jiǎn)要分析BannerViewPager的實(shí)現(xiàn)思路,具體的請(qǐng)讀者參考源碼~

實(shí)現(xiàn)自動(dòng)滾動(dòng)

首先,我們先思考一下,系統(tǒng)自帶的ViewPager是一個(gè)獨(dú)立控件,沒(méi)有指示器,也沒(méi)有自動(dòng)滾動(dòng)的功能,但是它是一個(gè)現(xiàn)成的,可左右滑動(dòng)的控件,我們肯定是需要ViewPager的,因此,我們可以利用一個(gè)布局,把ViewPager包裹起來(lái),同時(shí)在這個(gè)布局里面再放入indicator(指示器)。

那么,第一步,先新建BannerViewPager.java繼承自FrameLayout,而這個(gè)FrameLayout有兩個(gè)子元素:ViewPager和indicator。至于indicator,下面會(huì)說(shuō)到。在構(gòu)造函數(shù)內(nèi)對(duì)這兩個(gè)控件進(jìn)行初始化先:

public class BannerViewPager extends FrameLayout implements ViewPager.OnPageChangeListener {

 private ViewPager mViewPager;
 private ViewPagerIndicator mIndicator;
 private ViewPagerAdapter mAdapter;
 //...
 public BannerViewPager(Context context, AttributeSet attrs, int defStyleAttr) {
 super(context, attrs, defStyleAttr);
 this.mContext = context;
 initViews();
 }

 private void initViews() {
 //initialize the viewpager
 mViewPager = new ViewPager(mContext);
 ViewPager.LayoutParams lp = new ViewPager.LayoutParams();
 lp.width = ViewPager.LayoutParams.MATCH_PARENT;
 lp.height = ViewPager.LayoutParams.MATCH_PARENT;
 mViewPager.setLayoutParams(lp);

 //initialize the indicator
 mIndicator = new ViewPagerIndicator(mContext);
 FrameLayout.LayoutParams indicatorlp = new FrameLayout.LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);
 indicatorlp.gravity = Gravity.BOTTOM | Gravity.CENTER;
 indicatorlp.bottomMargin = 20;
 mIndicator.setLayoutParams(indicatorlp);
 }
 //省略...
}

這里沒(méi)什么好說(shuō)的,主要是對(duì)ViewPager和ViewPagerIndicator進(jìn)行初始化,設(shè)置它們的布局參數(shù)以便在FrameLayout中得到正確的顯示。

接著,對(duì)ViewPager實(shí)現(xiàn)自動(dòng)滾動(dòng),這個(gè)的實(shí)現(xiàn)原理也不難,我們只要知道每時(shí)每刻的ViewPager的滑動(dòng)狀態(tài)、當(dāng)前的page position值即可,而ViewPager有這樣一個(gè)監(jiān)聽(tīng)器:ViewPager.OnPageChangeListener,只要ViewPager進(jìn)行了滑動(dòng),就會(huì)回調(diào)這個(gè)監(jiān)聽(tīng)器的如下幾個(gè)方法:

public interface OnPageChangeListener {
 //只要ViewPager進(jìn)行了滑動(dòng),該方法就會(huì)回調(diào)
 public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels);
 //當(dāng)前頁(yè)面被選定的時(shí)候,回調(diào)
 public void onPageSelected(int position);
 //ViewPager的狀態(tài)發(fā)生改變的時(shí)候,回調(diào)
 public void onPageScrollStateChanged(int state);
}

那么,我們?yōu)閂iewPager設(shè)置監(jiān)聽(tīng)器(調(diào)用addOnPageChangeListener方法),并且重寫(xiě)這幾個(gè)方法以實(shí)現(xiàn)我們的需求:

 //保存當(dāng)前的position值
 private int mCurrentPosition;
 //viewpager's rolling state
 private int mViewPagerScrollState;

 @Override
 public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
 setIndicator(position,positionOffset); //下面會(huì)講到
 }

 @Override
 public void onPageSelected(int position) {
 mCurrentPosition = position;
 }

 @Override
 public void onPageScrollStateChanged(int state) {
 if(state == ViewPager.SCROLL_STATE_DRAGGING){
  mViewPagerScrollState = ViewPager.SCROLL_STATE_DRAGGING;
 }else if(state == ViewPager.SCROLL_STATE_IDLE){
  mReleasingTime = (int) System.currentTimeMillis();
  mViewPagerScrollState = ViewPager.SCROLL_STATE_IDLE;
 }
 }

每當(dāng)當(dāng)前頁(yè)面被選中的時(shí)候,就會(huì)調(diào)用onPageSelected方法,此時(shí)保存當(dāng)前position值。那么,什么叫做當(dāng)前頁(yè)面被選中呢?經(jīng)過(guò)實(shí)驗(yàn)驗(yàn)證,當(dāng)一個(gè)Item被完全展示在ViewPager中的時(shí)候,就是選中狀態(tài),但如果當(dāng)前正在被手指拖動(dòng),即使下一個(gè)item滑動(dòng)到了中間位置,也不是選中狀態(tài)。接著,我們看onPageScrollStateChanged方法,當(dāng)ViewPager的狀態(tài)發(fā)生改變的時(shí)候,就會(huì)觸發(fā)。那么,**ViewPager的狀態(tài)改變是什么意思呢?**ViewPager有如下三種狀態(tài):IDLE,停止?fàn)顟B(tài),無(wú)手指觸摸;DRAGGING,正在被手指拖動(dòng);SETTLING,松開(kāi)手指的時(shí)候,ViewPager由于慣性向能滑到的最后一個(gè)位置滑去的狀態(tài)。我們重寫(xiě)的方法中,mViewPageSrollState記錄了ViewPager的實(shí)時(shí)狀態(tài),同時(shí)停止?fàn)顟B(tài)的時(shí)候,也記錄了一個(gè)mReleasingTime值,這個(gè)值的作用下面會(huì)介紹。通過(guò)這個(gè)監(jiān)聽(tīng)器,我們獲取到了mCurrentPosition和mViewPageScrollState這兩個(gè)值。

接下來(lái),我們要考慮自動(dòng)任務(wù)的問(wèn)題了。在Android中,自動(dòng)任務(wù)可以使用Handler和Runnable來(lái)實(shí)現(xiàn),通過(guò)postDelay方法來(lái)不斷實(shí)現(xiàn)循環(huán),代碼如下:

 private Handler mHandler = new Handler(){
 @Override
 public void handleMessage(Message msg) {
  switch (msg.what){
  case MESSAGE_AUTO_ROLLING:
   if(mCurrentPosition == mAdapter.getCount() - 1){
   mViewPager.setCurrentItem(0,true);
   }else {
   mViewPager.setCurrentItem(mCurrentPosition + 1,true);
   }
   postDelayed(mAutoRollingTask,mAutoRollingTime);
   break;
  case MESSAGE_AUTO_ROLLING_CANCEL:
   postDelayed(mAutoRollingTask,mAutoRollingTime);
   break;
  }
 }
 };
 /**
 * This runnable decides the viewpager should roll to next page or wait.
 */
 private Runnable mAutoRollingTask = new Runnable() {
 @Override
 public void run() {
  int now = (int) System.currentTimeMillis();
  int timediff = mAutoRollingTime;
  if(mReleasingTime != 0){
  timediff = now - mReleasingTime;
  }

  if(mViewPagerScrollState == ViewPager.SCROLL_STATE_IDLE){
  //if user's finger just left the screen,we should wait for a while.
  if(timediff >= mAutoRollingTime * 0.8){
   mHandler.sendEmptyMessage(MESSAGE_AUTO_ROLLING);
  }else {
   mHandler.sendEmptyMessage(MESSAGE_AUTO_ROLLING_CANCEL);
  }
  }else if(mViewPagerScrollState == ViewPager.SCROLL_STATE_DRAGGING){
  mHandler.sendEmptyMessage(MESSAGE_AUTO_ROLLING_CANCEL);
  }

 }
 };

在mAutoRollingTask這個(gè)Runnable內(nèi),我們根據(jù)不同的mViewPagerScrollState來(lái)決定是讓ViewPager滾動(dòng)到下一個(gè)page還是等待,因?yàn)槿绻脩舢?dāng)前正在觸摸ViewPage,那么肯定是不能自動(dòng)滾動(dòng)到下一頁(yè)的,此外,還有一種情況,就是當(dāng)用戶手指離開(kāi)屏幕的時(shí)候,需要等待一段時(shí)間才能開(kāi)始自動(dòng)滾動(dòng)任務(wù),否則會(huì)造成不好的用戶體驗(yàn),這也就是mReleasingTime的作用之處了。在Handler中,根據(jù)Runnable發(fā)送過(guò)來(lái)的不同信息來(lái)進(jìn)行不同的操作,如果需要滾動(dòng)到下一個(gè)頁(yè)面,則調(diào)用ViewPager#setCurrentItem方法來(lái)進(jìn)行滑動(dòng),該方法有兩個(gè)參數(shù),第一個(gè)參數(shù)是要滑動(dòng)的位置,第二個(gè)參數(shù)表示是否開(kāi)啟動(dòng)畫(huà)。

實(shí)現(xiàn)指示器

接下來(lái),我們來(lái)考慮,指示器怎么實(shí)現(xiàn)。指示器有如下需求:指示器由一系列圓點(diǎn)構(gòu)成,未被選中的Page所對(duì)應(yīng)的圓點(diǎn)為灰色,而選中的Page所對(duì)應(yīng)的圓點(diǎn)為橙色,橙色的圓點(diǎn)能隨著Page的滑動(dòng)而滑動(dòng)。當(dāng)ViewPage的數(shù)據(jù)變動(dòng)的時(shí)候,比如新增了頁(yè)面,那么指示器所包含的圓點(diǎn)也會(huì)隨著變多。

那么,我們可以這樣來(lái)實(shí)現(xiàn)需求:灰色的圓點(diǎn)作為Indicator的背景,通過(guò)onDraw()方法來(lái)繪制,而橙色圓點(diǎn)則通過(guò)一個(gè)子View來(lái)顯示,利用onLayout()方法來(lái)控制它的位置,這樣就能實(shí)現(xiàn)橙色圓點(diǎn)在灰色圓點(diǎn)上運(yùn)動(dòng)的效果了。而它們具體的位置控制,可以利用上面ViewPager.OnPageChangeListener#onPageScrolled方法來(lái)獲取具體的位置以及位置偏移百分比。

我們先來(lái)實(shí)現(xiàn)繪制部分,新建ViewPagerIndicator.java繼承自LinearLayout,先對(duì)屬性初始化:

public class ViewPagerIndicator extends LinearLayout {

 private Context mContext;
 private Paint mPaint;
 private View mMoveView; 
 //省略...

 public ViewPagerIndicator(Context context, AttributeSet attrs, int defStyleAttr) {
 super(context, attrs, defStyleAttr);
 this.mContext = context;
 init();
 }

 private void init() {
 //setOrientation(LinearLayout.HORIZONTAL);
 setWillNotDraw(false);
 mPaint = new Paint();
 mPaint.setAntiAlias(true);
 mPaint.setColor(Color.GRAY);

 mMoveView = new MoveView(mContext);
 addView(mMoveView);
 }

 @Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
 super.onMeasure(widthMeasureSpec, heightMeasureSpec);
 setMeasuredDimension(mPadding + (mRadius*2 + mPadding) * mItemCount,2*mRadius + 2*mPadding);
 }

 @Override
 protected void onDraw(Canvas canvas) {
 super.onDraw(canvas);
 for(int i = 0;i < mItemCount;i++){
  canvas.drawCircle(mRadius + mPadding + mRadius * i *2 + mPadding * i,
   mRadius + mPadding,mRadius,mPaint);
 }

 }

 //省略...

 private class MoveView extends View {
 private Paint mPaint;

 public MoveView(Context context) {
  super(context);
  mPaint = new Paint();
  mPaint.setAntiAlias(true);
  mPaint.setColor(Color.argb(255,255,176,93));
 }

 @Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  setMeasuredDimension(mRadius*2,mRadius*2);
 }

 @Override
 protected void onDraw(Canvas canvas) {
  super.onDraw(canvas);
  canvas.drawCircle(mRadius,mRadius,mRadius,mPaint);
 }
 }
}

從上面的代碼可以看到,在init()方法內(nèi),我們調(diào)用了setWillNotDraw(false)方法,這個(gè)方法有什么用呢?如果有寫(xiě)過(guò)自定義View的讀者應(yīng)該知道,ViewGroup默認(rèn)是不會(huì)調(diào)用它自身的onDraw()方法的,只有調(diào)用了該方法設(shè)置為false或者給ViewGroup設(shè)置一種背景顏色的情況下才會(huì)調(diào)用onDraw()方法。

解決了這個(gè)問(wèn)題后,我們來(lái)看onMeasure()方法,在這個(gè)方法內(nèi),我們要對(duì)該indicator的寬高做出測(cè)量,以便接下來(lái)的布局和繪制流程,而對(duì)于我們的需求而言,只要該布局能夠包裹住我們的指示器,并且四邊留有一定的空間即可,那么布局的寬度就與Page的數(shù)量有關(guān)了。為了方便起見(jiàn),這里先給一個(gè)默認(rèn)值,比如5個(gè)Page,那么對(duì)應(yīng)5個(gè)灰色的圓點(diǎn)。
我們接著看onDraw()方法,這個(gè)方法內(nèi)部,根據(jù)mItemCount的數(shù)量,來(lái)進(jìn)行繪制圓形,這里沒(méi)什么好講的,只要注意他們之間的距離就可以了。

接著,我們來(lái)繪制橙色的圓點(diǎn),新建一個(gè)內(nèi)部類,繼承自View,同樣通過(guò)onMeasure、onDraw方法來(lái)進(jìn)行測(cè)量、繪制流程,只不過(guò)顏色變了而已。

好了,繪制部分就完成了,接下來(lái)就是讓這個(gè)MoveView進(jìn)行移動(dòng)了,由于要使MoveView配合Page的滑動(dòng)而滑動(dòng),我們需要Page的具體位置以及位置偏移量,而這兩個(gè)數(shù)值是在BannerViewPager的內(nèi)部中獲得的,所以我們可以在BannerViewPager中,每一次調(diào)用onPageScrolled方法的時(shí)候,來(lái)調(diào)用我們的ViewPagerIndicator的一個(gè)方法,而在這個(gè)方法內(nèi)部,來(lái)請(qǐng)求布局,這樣就能實(shí)現(xiàn)MoveView隨著Page的滑動(dòng)而滑動(dòng)的效果了,具體如下:

public class ViewPagerIndicator extends LinearLayout {
 //以上省略..

 public void setPositionAndOffset(int position,float offset){
 this.mCurrentPosition = position;
 this.mPositionOffset =offset;
 requestLayout();
 }
 @Override
 protected void onLayout(boolean changed, int l, int t, int r, int b) {
 super.onLayout(changed, l, t, r, b);
 mMoveView.layout(
  (int) (mPadding + mDistanceBtwItem * (mCurrentPosition + mPositionOffset) ),
  mPadding,
  (int) (mDistanceBtwItem * ( 1 + mCurrentPosition + mPositionOffset) ),
  mPadding+mRadius*2);
 }
}

在setPositionAndOffset方法內(nèi)調(diào)用了requestLayout()方法,這個(gè)方法會(huì)導(dǎo)致View樹(shù)的測(cè)量、布局、重繪流程的發(fā)生,因此在onLayout方法內(nèi),通過(guò)mCurrentPosition、mPositionOffset這兩個(gè)值來(lái)控制MoveView的位置就可以了。

好了,到現(xiàn)在為止,ViewPagerIndicator基本已經(jīng)完成了,但是還有一個(gè)問(wèn)題,如果適配器里面的數(shù)據(jù)刷新了,page的數(shù)量變多了,而指示器的數(shù)目卻依然沒(méi)變,上面我們使用的mItemCount是默認(rèn)值,為5個(gè)。因此,我們必須在數(shù)據(jù)刷新的時(shí)候,及時(shí)通知Indicator來(lái)增加指示器的數(shù)目。但是,我們進(jìn)一步想想,數(shù)據(jù)列表保存在Adapter中,如果ViewPagerIndicator想要獲取數(shù)據(jù),那就要得到Adapter的一個(gè)引用,或者說(shuō)Adapter需要得到ViewPagerIndicator的引用以便能夠通知它,如果這樣做的話,相當(dāng)于把兩個(gè)相關(guān)性不大的類聯(lián)系到了一起,耦合度過(guò)高,這樣不利于以后的維護(hù)。

因此,這里筆者采用了觀察者模式來(lái)實(shí)現(xiàn)Adapter數(shù)據(jù)刷新時(shí)通知ViewPagerIndicator的這樣一個(gè)需求。先新建兩個(gè)接口,一個(gè)是DataSetSubscriber,觀察者;另一個(gè)是DataSetSubject,被觀察者。

public interface DataSetSubscriber { 
 void update(int count);
}


public interface DataSetSubject { 
 void registerSubscriber(DataSetSubscriber subscriber); 
 void removeSubscriber(DataSetSubscriber subscriber); 
 void notifySubscriber();
}

這里實(shí)現(xiàn)思路是這樣的:在BannerViewPager內(nèi)實(shí)現(xiàn)一個(gè)DataSetSubscriber(觀察者),在ViewPageAdapter內(nèi)實(shí)現(xiàn)DataSetSubject(被觀察者),通過(guò)registerSubscriber方法進(jìn)行注冊(cè),當(dāng)ViewPageAdapter的數(shù)據(jù)列表發(fā)生變動(dòng)的時(shí)候,回調(diào)DataSetSubscriber的update()方法,并把當(dāng)前的數(shù)據(jù)長(zhǎng)度作為參數(shù)傳遞進(jìn)來(lái),而B(niǎo)annerViewPager再進(jìn)一步調(diào)用ViewPagerIndicator的方法來(lái)重新布局即可。

先來(lái)看ViewPagerIndicator.java:

public class ViewPagerAdapter extends PagerAdapter implements DataSetSubject {

 private List<DataSetSubscriber> mSubscribers = new ArrayList<>();
 private List<? extends View> mDataViews;
 private OnPageClickListener mOnPageClickListener;

 /**
 * 構(gòu)造函數(shù)
 * @param mDataViews view列表
 */
 public ViewPagerAdapter(List<? extends View> mDataViews,OnPageClickListener listener) {
 this.mDataViews = mDataViews;
 this.mOnPageClickListener = listener;
 }

 //省略...

 @Override
 public void notifyDataSetChanged() {
 super.notifyDataSetChanged();
 notifySubscriber();
 }

 @Override
 public void registerSubscriber(DataSetSubscriber subscriber) {
 mSubscribers.add(subscriber);
 }

 @Override
 public void removeSubscriber(DataSetSubscriber subscriber) {
 mSubscribers.remove(subscriber);
 }

 @Override
 public void notifySubscriber() {
 for(DataSetSubscriber subscriber : mSubscribers){
  subscriber.update(getCount());
 }
 }
}```

由于數(shù)據(jù)列表的變動(dòng)一般都會(huì)調(diào)用notifyDataSetChanged()方法,所以我們?cè)谶@個(gè)方法內(nèi)再調(diào)用notifySubscriber()方法即可。而在BannerViewPager,則實(shí)現(xiàn)DataSetSubscriber的update()方法即可,如下所示:

```java
public void setAdapter(ViewPagerAdapter adapter){
 mViewPager.setAdapter(adapter);
 mViewPager.addOnPageChangeListener(this);

 mAdapter = adapter;
 mAdapter.registerSubscriber(new DataSetSubscriber() {
 @Override
 public void update(int count) {
  mIndicator.setItemCount(count);
 }
 });

 //add the viewpager and the indicator to the container.
 addView(mViewPager);
 addView(mIndicator);

 //start the auto-rolling task if needed
 if(isAutoRolling){
 postDelayed(mAutoRollingTask,mAutoRollingTime);
 }

}

在update()方法內(nèi),調(diào)用了ViewPagerIndicator#setItemCount方法,從而重新布局。
那么,指示器也實(shí)現(xiàn)完畢了。

實(shí)現(xiàn)Page的點(diǎn)擊事件處理

還有最后一個(gè)需求,就是對(duì)Page的點(diǎn)擊進(jìn)行處理,因?yàn)橥鵙iewPager的內(nèi)容只是一個(gè)概括性的內(nèi)容,為了得到更加詳細(xì)的信息,用戶通常會(huì)點(diǎn)擊它的item從而打開(kāi)一個(gè)新的頁(yè)面,這樣就需要我們對(duì)點(diǎn)擊事件進(jìn)行處理了。其實(shí)實(shí)現(xiàn)方式不難,思路類似于筆者之前在RecyclerView的相關(guān)文章的處理點(diǎn)擊事件中的方式,通過(guò)定義一個(gè)新的接口:OnPageClickListener,定義一個(gè)onPageClick方法。如下:

public interface OnPageClickListener { 
 void onPageClick(View view,int position);
}

只要在item view初始化的時(shí)候,給每個(gè)item view都設(shè)置一個(gè)View.OnClickListener,并且在onClick方法里面調(diào)用我們的onPageClick方法即可。

具體如下所示,ViewPagerAdapter:

@Override
public View instantiateItem(ViewGroup container, int position) {
 View view = mDataViews.get(position);
 final int i = position;
 if(mOnPageClickListener != null){
 view.setOnClickListener(new View.OnClickListener() {
  @Override
  public void onClick(View v) {
  mOnPageClickListener.onPageClick(v,i);
  }
 });
 }

 container.addView(view);
 return view;
}

在構(gòu)建適配器的時(shí)候,同時(shí)實(shí)現(xiàn)OnPageClickListener即可。

以上便是本文的全部?jī)?nèi)容,非常感謝你的閱讀~
歡迎到GitHub中獲取本文的源碼,歡迎star or fork。再次感謝!

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Android手電筒兼容各個(gè)手機(jī)與版本

    Android手電筒兼容各個(gè)手機(jī)與版本

    這篇文章主要為大家詳細(xì)介紹了Android手電筒兼容各個(gè)手機(jī)與版本,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-09-09
  • Android10?Binder原理概述深入解析

    Android10?Binder原理概述深入解析

    這篇文章主要為大家介紹了Android10?Binder原理概述深入解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-10-10
  • Android自定義谷歌風(fēng)格ProgressBar

    Android自定義谷歌風(fēng)格ProgressBar

    這篇文章主要為大家詳細(xì)介紹了Android自定義谷歌風(fēng)格ProgressBar的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-02-02
  • Flutter滾動(dòng)組件之ListView使用方法詳解

    Flutter滾動(dòng)組件之ListView使用方法詳解

    這篇文章主要為大家詳細(xì)介紹了Flutter滾動(dòng)組件之ListView的使用方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • android實(shí)現(xiàn)上滑屏幕隱藏底部菜單欄的示例

    android實(shí)現(xiàn)上滑屏幕隱藏底部菜單欄的示例

    這篇文章主要介紹了android實(shí)現(xiàn)上滑屏幕隱藏底部菜單欄的示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-02-02
  • Android實(shí)現(xiàn)俄羅斯方塊

    Android實(shí)現(xiàn)俄羅斯方塊

    這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)俄羅斯方塊游戲 ,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-06-06
  • Android生存指南之:解Bug策略與思路問(wèn)題的詳解

    Android生存指南之:解Bug策略與思路問(wèn)題的詳解

    本篇文章是對(duì)Android 解Bug策略與思路的問(wèn)題進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • Android使用自定義View實(shí)現(xiàn)橫行時(shí)間軸效果

    Android使用自定義View實(shí)現(xiàn)橫行時(shí)間軸效果

    這篇文章主要給大家介紹了關(guān)于Android使用自定義View實(shí)現(xiàn)橫行時(shí)間軸效果的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Android具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-12-12
  • Android MessageQueue消息隊(duì)列主要作用詳解

    Android MessageQueue消息隊(duì)列主要作用詳解

    Android 消息機(jī)制主要指的是 Handler 的運(yùn)行機(jī)制及其所依賴的 MessageQueue 和 Looper 的工作過(guò)程,Handler、MessageQueue、Looper組成一個(gè)相互聯(lián)系的整體。本文先從 MessageQueue 的源碼來(lái)說(shuō)明其實(shí)現(xiàn)原理
    2023-02-02
  • Android使用文件進(jìn)行IPC

    Android使用文件進(jìn)行IPC

    這篇文章主要為大家詳細(xì)介紹了Android使用文件進(jìn)行IPC,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-12-12

最新評(píng)論