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

手把手教你用ViewPager自定義實現(xiàn)Banner輪播

 更新時間:2016年09月12日 10:47:54   作者:yanzhenjie1003  
這篇文章主要手把手教你用ViewPager自定義實現(xiàn)Banner輪播,具有一定的參考價值,感興趣的小伙伴們可以參考一下

歡迎大家關(guān)注Android開源網(wǎng)絡(luò)框架NoHttp:https://github.com/yanzhenjie/NoHttp 

  我們在實際開發(fā)中,很多App都會在做一個廣告輪播器(可能是圖片,可能是其他View),很多同學(xué)都是使用別人封裝好的或者直接使用ViewPager自己來改,但是有人可能并不理解里面的原理,或者有人遇到了手勢滑動沖突。我們今天就用150行代碼實現(xiàn)一自定義的廣告輪播器并不干擾原來View滑動事件。
  本例代碼源碼及Demo傳送門

效果演示

需求分析、解決方案

  輪播器最重要的幾個特點就是:自動滾動、手動滑動、滾動方向、每個Item顯示時間。因此我們設(shè)計提供以下幾個方法供外部調(diào)用:

/**
 * 設(shè)置每個Item的播放時間,默認3000毫秒
 */
public void setShowTime(int showTimeMillis);

/**
 * 設(shè)置滾動方向,默認向左滾動
 */
public void setDirection(Direction direction);

/**
 * 開始自動滾動
 */
public void start();

/**
 * 停止自動滾動
 */
public void stop();

/**
 * 播放上一個
 */
public void previous();

/**
 * 播放下一個
 */
public void next();

  仔細看過上面方法的同學(xué)會發(fā)現(xiàn),和我們的分析想比,還缺少一個手動滑動的方法,我們知道手勢滑動肯定要用到onTouch等方法,所以我們想到v4包下ViewPager自帶滑動效果,而且可以代碼控制跳轉(zhuǎn)到某個Item。因此我們自定義View繼承ViewPager不就完美解決了。
  我們看到上面的方法中有一個Direction類,這個類不是系統(tǒng)的,是達哥自定義的方向控制枚舉,目前最常見的輪播方向無非就是左右輪播(上下本次先不討論),代碼如下:

public enum Direction {
 /**
 * 向左行動,播放的下一張應(yīng)該是右邊的
 */
 LEFT,

 /**
 * 向右行動,播放的下一張應(yīng)該是左邊的
 */
 RIGHT
}

自定義View如何實現(xiàn)以及原理

  上面分析到需要繼承ViewPager,so我們先結(jié)合上面的幾個方法把完整的代碼擼起來:

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;

 /**
 * 設(shè)置播放時間,默認3秒
 *
 * @param showTimeMillis 毫秒
 */
 public void setShowTime(int showTimeMillis) {
 this.showTime = showTime;
 }

 /**
 * 設(shè)置滾動方向,默認向左滾動
 *
 * @param direction 方向
 */
 public void setDirection(Direction direction) {
 this.direction = direction;
 }

 /**
 * 開始
 */
 public void start() {
 // TODO 待實現(xiàn)開始播放
 }

 /**
 * 停止
 */
 public void stop() {
 // TODO 待實現(xiàn)停止播放
 }

 /**
 * 播放上一個
 */
 public void previous() {
 // TODO 待實現(xiàn)播放上一個
 }

 /**
 * 播放下一個
 */
 public void next() {
 // TODO 待實現(xiàn)播放下一個
 }

 public enum Direction {
 /**
  * 向左行動,播放的應(yīng)該是右邊的
  */
 LEFT,

 /**
  * 向右行動,播放的應(yīng)該是左邊的
  */
 RIGHT
 }
}

  setShowTime(int showTimeMillis)方法和setDirection(Direction direction)就是記錄一下某一個狀態(tài)而已,現(xiàn)在已經(jīng)簡單的實現(xiàn)了,重點就是開始播放和停止播放。   

定時輪播的原理分析和實現(xiàn)

  前方高能,各位看官小心褲子別掉了。現(xiàn)在我們使用ViewPager最主要的就是自動播放了,所以我們需要一個定時器去執(zhí)行任務(wù),but這樣子就得用到Handler,就有點小題大做了。這里介紹View的兩個方法:

// 線程將被添加到消息隊列,這個線程將會在UI線程(主線程)運行。
public boolean post(Runnable action);

// 線程將被添加到消息隊列,在指定的時間之后運行,這個線程將會在UI線程(主線程)運行。
public boolean postDelayed(Runnable action, long delayMillis);

  看到第二個方法猶如醍醐灌頂啊有木有,既然是所有View都有的方法,ViewPager必須有啊,這樣不就可以在主線程定時發(fā)布一個任務(wù)了嗎?所以我們這里寫一個Runnable來做這個定時任務(wù)。

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

  這里看到有一個play(direction);的方法待我們?nèi)崿F(xiàn),我們暫且把這個方法先放一放,我們先來看怎么利用這個private Runnable player完成開始播放和停止播放。   

實現(xiàn)開始播放和停止播放

  開始播放時我們?yōu)榱俗尞?dāng)前顯示的圖片顯示showTime的時間,所以我們利用postDelayed(Runnable action, long delayMillis);方法在showTime時間之后觸發(fā)private Runnable player:

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

  停止播放,我們把這個線程給取消了就行了,因此停止的方法的實現(xiàn)是:

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

  但是為了防止開發(fā)者不停的調(diào)用start方法造成卡死現(xiàn)象,我們在start中做個優(yōu)化,每次star前先把之前private Runable player移除了,因此start方法完整的代碼是:

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

核心重點:如何根據(jù)方向播放上一張和下一張

  本例的核心和重點來了,現(xiàn)在回過頭去實現(xiàn)剛才擱置的play(direction);方法,它要根據(jù)播放的方向來播放上一張和下一張,我們具體看代碼,尤其要細細品味注釋哦:

/**
 * 執(zhí)行播放
 *
 * @param direction 播放方向
 */
private synchronized void play(Direction direction) {
 // 拿到ViewPager的適配器
 PagerAdapter pagerAdapter = getAdapter();
 if (pagerAdapter != null) {// 判空
 // Item數(shù)量
 int count = pagerAdapter.getCount();
 // ViewPager現(xiàn)在顯示的第幾個?
 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);// 播放根據(jù)方向計算出來的position的item
 }

 // 這就是當(dāng)可以循環(huán)播放的重點,每次播放完成后,再次開啟一個定時任務(wù)
 start();
}

  到這里其實我們已經(jīng)實現(xiàn)輪播啦,但是我們在使用的時候發(fā)現(xiàn)存在一種情況,當(dāng)我們用手指剛滑完一張,緊接著第二張又出來了,不賣關(guān)子了,原因就是我們手指滑動的時候private Runnable player這個任務(wù)沒有停止,所以我們在手指滑動時停止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();
 }
 });
}

  有些同學(xué)可能不知道為什么不在構(gòu)造方法中而要在onFinishInflate中addOnPageChangeListener,是因為這個方法會在view被加載完成后調(diào)用,所以我們在這里做一些初始化的工作比較合理。
  自定義ViewPager的完整代碼如下:

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;
 /**
 * 設(shè)置播放時間,默認3秒
 *
 * @param showTimeMillis 毫秒
 */
 public void setShowTime(int showTimeMillis) {
 this.showTime = showTime;
 }

 /**
 * 設(shè)置滾動方向,默認向左滾動
 *
 * @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);
 }

 /**
 * 執(zhí)行播放
 *
 * @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 {
 /**
  * 向左行動,播放的應(yīng)該是右邊的
  */
 LEFT,
  /**
  * 向右行動,播放的應(yīng)該是左邊的
  */
 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();
  }
 });
 }
}


如何使用

  其實我們沒有對ViewPager做什么太大的干涉,所以我們使用和原生的沒有什么區(qū)別。這里有幾個注意的地方也寫出來,免得有人踩坑。

如果使用自定ViewPager

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

// 以下兩個方法不是必須的,因為有默認值
autoPlayViewPage.setDirection(AutoPlayViewPager.Direction.LEFT);// 設(shè)置播放方向
autoPlayViewPage.setCurrentItem(200); // 設(shè)置每個Item展示的時間

autoPlayViewPage.start(); // 開始輪播

如何優(yōu)化Adapter

  其實我們看到就是多調(diào)用了一個star方法,但是還不夠,我們在適配器中還要做一點點小事情。為了能讓輪播無限循環(huán),所以我們在getCount中返回int的最大值:

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

  resIds是我們的數(shù)據(jù)源。該了這個Count后,我們的instantiateItem()方法也要修改,不然會發(fā)生下標(biāo)越界的異常,我們在拿到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(jb51.net).rar

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

相關(guān)文章

  • Android NDK開發(fā)(C語言字符串)

    Android NDK開發(fā)(C語言字符串)

    這篇文章主要介紹了Android NDK開發(fā) C語言字符串 ,主要以字符數(shù)組、字符指針及一些字符串常用的方法的方法未來全文展開內(nèi)容,需要的朋友可以參考一下
    2021-12-12
  • Android編程學(xué)習(xí)之異步加載圖片的方法

    Android編程學(xué)習(xí)之異步加載圖片的方法

    這篇文章主要介紹了Android編程學(xué)習(xí)之異步加載圖片的方法,以實例形式較為詳細的分析了Android異步加載圖片所涉及的頁面布局及功能實現(xiàn)技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-10-10
  • Ubuntu中為Android實現(xiàn)Application Frameworks層增加硬件訪問服務(wù)

    Ubuntu中為Android實現(xiàn)Application Frameworks層增加硬件訪問服務(wù)

    本文主要介紹Android實現(xiàn) Application Frameworks層增加硬件訪問服務(wù),這里對實現(xiàn)增加硬件訪問服務(wù)的功能做出了詳細的工作流程,并提供示例代碼,有需要的小伙伴參考下
    2016-08-08
  • Android使用getIdentifier()獲取資源Id的方法

    Android使用getIdentifier()獲取資源Id的方法

    這篇文章主要介紹了Android使用getIdentifier()獲取資源Id的方法,涉及Android針對控件資源的相關(guān)操作技巧,需要的朋友可以參考下
    2016-08-08
  • Android studio實現(xiàn)PopupWindow彈出框效果

    Android studio實現(xiàn)PopupWindow彈出框效果

    這篇文章主要為大家詳細介紹了Android studio實現(xiàn)PopupWindow彈出框效果,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-10-10
  • 微信小程序在安卓的白屏問題原因及改進講解

    微信小程序在安卓的白屏問題原因及改進講解

    今天小編就為大家分享一篇關(guān)于微信小程序在安卓的白屏問題原因及改進講解,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-02-02
  • 詳解Android使用Html.fromHtml需要注意的地方

    詳解Android使用Html.fromHtml需要注意的地方

    本篇文章主要介紹了詳解Android使用Html.fromHtml需要注意的地方,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-07-07
  • MediaPlayer音頻與視頻播放方法示例介紹

    MediaPlayer音頻與視頻播放方法示例介紹

    這篇文章主要為大家介紹了MediaPlayer音頻與視頻播放方法示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-04-04
  • Android實現(xiàn)圖片文字輪播特效

    Android實現(xiàn)圖片文字輪播特效

    這篇文章主要介紹了Android圖片文字輪播效果,分別實現(xiàn)圖片和文字自動滾動,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-01-01
  • Android StringBuffer的使用方法詳解

    Android StringBuffer的使用方法詳解

    StringBuffer類和String一樣,也用來代表字符串,只是由于StringBuffer的內(nèi)部實現(xiàn)方式和String不同,所以StringBuffer在進行字符串處理時,不生成新的對象,在內(nèi)存使用上要優(yōu)于String類
    2017-07-07

最新評論