手を取って教えます。Viewer Pagerでカスタマイズして、Bannerの順番放送を実現します。


AndroidオープンソースネットワークフレームNoHttp:https://github.com/yanzhenjie/NoHttpに注目してください。 
私達は実際に開発しています。多くのアプリは広告のルーレットを作っています。(写真かもしれません。他のViewかもしれません。)多くの学生は他の人のパッケージを使っています。あるいは直接にView Pagerを使って自分で変えますが、中の原理を理解していない人もいます。今日は150行のコードを使ってカスタマイズした広告ルーニーを実現します。元々のビュースライドイベントに邪魔しませんでした。
この例のコードのソースコードとDemo転送ゲート
効果のデモンストレーション

需要分析、ソリューション
ルーニーの最も重要ないくつかの特徴は、自動スクロール、手動スライド、スクロール方向、Item毎の表示時間です。したがって、外部からの呼び出しのために以下のいくつかの方法を設計して提供します。

/**
 *     Item     ,  3000  
 */
public void setShowTime(int showTimeMillis);

/**
 *       ,      
 */
public void setDirection(Direction direction);

/**
 *       
 */
public void start();

/**
 *       
 */
public void stop();

/**
 *      
 */
public void previous();

/**
 *      
 */
public void next();

上記の方法をよく見ていると、私たちの分析と比べて、手動でスライドする方法が足りないと思います。手でスライドするには必ずonTouchなどの方法が必要だと知っています。だから、v 4カバンの下で、ViewPagerがスライド効果を持っていると思います。コード制御もできます。だから私達はViewをカスタマイズしてView Pagerを継承して完璧に解決したのではないですか?
上記の方法の中にDirection類があることを見ました。この類はシステムではなくて、達兄が自分で作った方向で列挙を制御しています。現在最も一般的なロードショーの方向は右のロードショーだけです。コードは以下の通りです。

public enum Direction {
 /**
 *     ,            
 */
 LEFT,

 /**
 *     ,            
 */
 RIGHT
}

Viewのカスタマイズと原理
上記の分析はViewer Pagerを継承する必要があります。そして私達は先に上のいくつかの方法を組み合わせて完全なコードをまとめます。

public class AutoPlayViewPager extends ViewPager {

 public AutoPlayViewPager(Context context) {
 super(context);
 }

 public AutoPlayViewPager(Context context, AttributeSet attrs) {
 super(context, attrs);
 }

 /**
 *     
 */
 private int showTime = 3 * 1000;
 /**
 *     
 */
 private Direction direction = Direction.LEFT;

 /**
 *       ,  3 
 *
 * @param showTimeMillis   
 */
 public void setShowTime(int showTimeMillis) {
 this.showTime = showTime;
 }

 /**
 *       ,      
 *
 * @param direction   
 */
 public void setDirection(Direction direction) {
 this.direction = direction;
 }

 /**
 *   
 */
 public void start() {
 // TODO        
 }

 /**
 *   
 */
 public void stop() {
 // TODO        
 }

 /**
 *      
 */
 public void previous() {
 // TODO         
 }

 /**
 *      
 */
 public void next() {
 // TODO         
 }

 public enum Direction {
 /**
  *     ,         
  */
 LEFT,

 /**
  *     ,         
  */
 RIGHT
 }
}

set Show Timeメソッドとset Directionは、ある状態を記録するだけです。簡単に実現しました。放送開始と停止がポイントです。  
タイミングルーニーの原理分析と実現
前方の高エネルギーは、ズボンを落とさないように注意してください。今はViewer Pagerを使っていますが、一番重要なのは自動放送です。だから私たちはタイマーを使って任務を遂行します。butはこのようにHandlerを使わなければなりません。ちょっと大げさです。ここではViewの二つの方法を紹介します。

//            ,       UI  (   )  。
public boolean post(Runnable action);

//            ,          ,       UI  (   )  。
public boolean postDelayed(Runnable action, long delayMillis);

二つ目の方法を見たら醍醐の頭のようです。有木さん、すべてのViewにある方法ですから、Viewer Pagerは必ずあります。これでメインスレッドのタイミングで任務を発表することができますか?だから、ここでRunnableを書いて、この定時任務をします。

/**
 *    
 */
private Runnable player = new Runnable() {
 @Override
 public void run() {
 play(direction);
 }
};

ここでプレイを見ました。の方法は私達が実現することを待って、私達はしばらくこの方法を放して、私達は先にどのようにこのprvate Runnable playerを利用して完成して放送を開始して停止することを見にきます。  
再生開始と停止を実現
放送開始時には、現在表示されている画像にショータイムを表示させるために、postDelayedを利用します。方法はshowTime時間後にprvate Runnable playerをトリガする:

/**
 *   
 */
public void start() {
 postDelayed(player, showTime);
}

再生を中止して、私達はこのスレッドをキャンセルすればいいです。ですので、停止する方法の実現は以下の通りです。

/**
 *   
 */
public void stop() {
 removeCallbacks(player);
}

しかし、開発者がストップしないようにstartメソッドを起動してカードが死ぬ現象を引き起こすことを防ぐために、私達はstartの中で最適化をして、毎回starの前に先にprvate Runable playerを除去しました。

/**
 *   
 */
public void start() {
 stop();
 postDelayed(player, showTime);
}

重点:どうやって前の方と次の方を再生しますか?
本例の核心と重点は来て、今振り返って先ほど棚上げしたプレイを実現します。方法としては、再生方向によって前のページと次のページを再生します。コードを具体的に見て、特にコメントをよく吟味してください。

/**
 *     
 *
 * @param direction     
 */
private synchronized void play(Direction direction) {
 //   ViewPager    
 PagerAdapter pagerAdapter = getAdapter();
 if (pagerAdapter != null) {//   
 // Item  
 int count = pagerAdapter.getCount();
 // ViewPager        ?
 int currentItem = getCurrentItem();
 switch (direction) {
  case LEFT://        ,currentItem+1     
  currentItem++;

  //   +      ,     
  if (currentItem >= count)
   currentItem = 0;
  break;
  case RIGHT://        ,currentItem-1     
  currentItem--;

  //   -     ,      
  if (currentItem < 0)
   currentItem = count - 1;
  break;
 }
 setCurrentItem(currentItem);//            position item
 }

 //              ,       ,          
 start();
}

ここに来て、実は私達はもう輪播を実現しました。でも私達は使う時に一つの状況があります。私達は指で一枚滑ったばかりで、次の二枚目がまた出てきました。もう大丈夫です。その原因は私達の指が滑る時にprvate Runnable playerという任務は停止していません。指を離す時にもう一度playerを開けます。

@Override
protected void onFinishInflate() {
 addOnPageChangeListener(new OnPageChangeListener() {
 @Override
 public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
 }

 @Override
 public void onPageSelected(int position) {
 }

 @Override
 public void onPageScrollStateChanged(int state) {
  if (state == SCROLL_STATE_IDLE)
  start();
  else if (state == SCROLL_STATE_DRAGGING)
  stop();
 }
 });
}

いくつかの学生はなぜ構造方法ではなくオンフィニッシュInflateの中でaddOnPageChape Listenerが必要かを知らないかもしれません。この方法はviewでロードされた後に呼び出されるので、ここで初期化の仕事をするのが合理的です。
カスタムView Pagerのフルコードは以下の通りです。

package com.yolanda.autoviewpager;

import android.content.Context;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;

/**
 * <p> ViewPager         。</p>.
 * 
 * @author Yolanda; 
 */
public class AutoPlayViewPager extends ViewPager {

 public AutoPlayViewPager(Context context) {
 super(context);
 }

 public AutoPlayViewPager(Context context, AttributeSet attrs) {
 super(context, attrs);
 }

 /**
 *     
 */
 private int showTime = 3 * 1000;
 /**
 *     
 */
 private Direction direction = Direction.LEFT;
 /**
 *       ,  3 
 *
 * @param showTimeMillis   
 */
 public void setShowTime(int showTimeMillis) {
 this.showTime = showTime;
 }

 /**
 *       ,      
 *
 * @param direction   
 */
 public void setDirection(Direction direction) {
 this.direction = direction;
 }

 /**
 *   
 */
 public void start() {
 stop();
 postDelayed(player, showTime);
 }

 /**
 *   
 */
 public void stop() {
 removeCallbacks(player);
 }

 /**
 *      
 */
 public void previous() {
 if (direction == Direction.RIGHT) {
  play(Direction.LEFT);
 } else if (direction == Direction.LEFT) {
  play(Direction.RIGHT);
 }
 }

 /**
 *      
 */
 public void next() {
 play(direction);
 }

 /**
 *     
 *
 * @param direction     
 */
 private synchronized void play(Direction direction) {
 PagerAdapter pagerAdapter = getAdapter();
 if (pagerAdapter != null) {
  int count = pagerAdapter.getCount();
  int currentItem = getCurrentItem();
  switch (direction) {
  case LEFT:
   currentItem++;
   if (currentItem > count)
   currentItem = 0;
   break;
  case RIGHT:
   currentItem--;
   if (currentItem < 0)
   currentItem = count;
   break;
  }
  setCurrentItem(currentItem);
 }
 start();
 }

 /**
 *    
 */
 private Runnable player = new Runnable() {
 @Override
 public void run() {
  play(direction);
 }
 };

 public enum Direction {
 /**
  *     ,         
  */
 LEFT,
  /**
  *     ,         
  */
 RIGHT
 }

 @Override
 protected void onFinishInflate() {
 super.onFinishInflate();
 addOnPageChangeListener(new OnPageChangeListener() {
  @Override
  public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
  }

  @Override
  public void onPageSelected(int position) {
  }

  @Override
  public void onPageScrollStateChanged(int state) {
  if (state == SCROLL_STATE_IDLE)
   start();
  else if (state == SCROLL_STATE_DRAGGING)
   stop();
  }
 });
 }
}


どう使いますか
実は私達はViewer Pagerに対して何か大きな干渉をしていませんので、私達が使っているのは原生のものと変わらないです。ここには踏まれないように注意するところがあります。
自定View Pagerを使用すると

AutoPlayViewPager autoPlayViewPage = (AutoPlayViewPager) findViewById(R.id.view_pager);
autoPlayViewPage.setAdapter(bannerAdapter);

//            ,      
autoPlayViewPage.setDirection(AutoPlayViewPager.Direction.LEFT);//       
autoPlayViewPage.setCurrentItem(200); //     Item     

autoPlayViewPage.start(); //     

どのようにAdapterを最適化しますか
実は私達は多くstarの方法を使ったことを見ましたが、まだ足りないです。アダプターの中でまだちょっとしたことがあります。無限ループできるように、get Countでintの最大値を返します。

@Override
public int getCount() {
 return resIds == null ? 0 : Integer.MAX_VALUE;
}

レスIdsは私たちのデータソースです。このCountを使ったら、私達のinstantiateItem()方法も修正しなければなりません。さもなければ、オフラインの異常が発生します。私達はpositionを持ってから処理します。

@Override
public Object instantiateItem(ViewGroup container, int position) {
 position = position % resIds.size();
 Object xxoo = resIds.get(position);
 ...
}

本例のコードのソースコード:http://xiazai.jb51.net/201609/yuanma/AutoViewPager(jb 51.net)rar
以上が本文の全部です。皆さんの勉強に役に立つように、私たちを応援してください。