Android實現(xiàn)一個絲滑的自動輪播控件實例代碼
前言
現(xiàn)在很多的 App 都有自動輪播的 banner 界面,用于展示廣告圖片或者顯示當(dāng)前比較熱門的一些活動,除了具備比較酷炫的效果之外,通過輪播的方式來減少對界面的占用,也是很贊的一個設(shè)計點。本文主要是總結(jié)自動輪播控件的實現(xiàn)過程,以及對這類控件的一些優(yōu)化的技巧。
一、如何實現(xiàn)
在開始進(jìn)行我們的代碼編程之前,我們先要思考一下,在 Google 提供的官方 Api 里面,有沒有類似的控件實現(xiàn)了相似的功能,畢竟官方的控件大都經(jīng)過了時間的考驗,無論是穩(wěn)定性還是性能方面都是非常不錯的,如果我們能夠基于官方的控件進(jìn)行相應(yīng)的改造,控件的穩(wěn)定性也會有相對的保障。
在比較常見的主流控件里面,其實 ViewPager 和 RecyclerView 已經(jīng)實現(xiàn)了類似的功能,尤其是 ViewPager,可以說是已經(jīng)實現(xiàn)了我們這個控件的大部分功能,所以如果我們基于 ViewPager 來進(jìn)行改造的話,也能讓我們的輪播控件更加穩(wěn)定。
那 ViewPager 跟我們需要的自動輪播控件有多少差距呢,主要有兩個:
- 不支持自動播放
- 無法從最后一張滑動到第一張
所以我們主要是針對這兩部分進(jìn)行相應(yīng)的改造,從而實現(xiàn)我們自己的自動輪播控件。
1.1 實現(xiàn)自動輪播功能
要想實現(xiàn)自動輪播功能,我們最先想到的應(yīng)該是通過 Timer 或者 ScheduledExecutorService 來實現(xiàn)計時器的功能,然后讓 ViewPager 通過 serCurrentItem(int position) 方法,將當(dāng)前的 Item 設(shè)置為下一個 position 的數(shù)據(jù),但是如果通過定時器來實現(xiàn)的話,會有一個問題,那就是我們在需要讓 banner 進(jìn)行停止播放的時候就比較麻煩,所以通過 Handler 用 sendMessage 的形式,進(jìn)行事件的發(fā)送實現(xiàn) ViewPager 的自動輪播,以及某些場景的停止是比較合理的。
我們來看下代碼:
private static class AutoScrollHandler extends Handler {
private WeakReference<AutoScrollViewPager> mBannerRef;
private static final int MSG_CHANGE_SELECTION = 1;
AutoScrollHandler(AutoScrollViewPager autoScrollViewPager) {
mBannerRef = new WeakReference<>(autoScrollViewPager);
}
private void start() {
removeMessages(MSG_CHANGE_SELECTION);
sendEmptyMessageDelayed(MSG_CHANGE_SELECTION, AUTO_SCROLL_TIME);
}
private void stop() {
removeMessages(MSG_CHANGE_SELECTION);
}
@Override
public void handleMessage(Message msg) {
if (msg.what == MSG_CHANGE_SELECTION) {
if (mBannerRef == null || mBannerRef.get() == null) {
return;
}
AutoScrollViewPager banner = mBannerRef.get();
if (banner.mSelectedIndex == Integer.MAX_VALUE) {
int rightPos = banner.mSelectedIndex % banner.mBannerList.size();
banner.setCurrentItem(banner.getInitPosition() + rightPos + 1, true);
} else {
if (!hasMessages(MSG_CHANGE_SELECTION)) {
banner.setCurrentItem(banner.mSelectedIndex + 1, true);
sendEmptyMessageDelayed(MSG_CHANGE_SELECTION, AUTO_SCROLL_TIME);
}
}
}
}
}
可以看到,我們先傳入外部的 ViewPager,然后通過弱引用的形式防止內(nèi)存泄露,通過在 handlerMessage() 方法里面,調(diào)用 setCurrentItem() 方法,將當(dāng)前 ViewPager 的 Item 設(shè)置為對應(yīng)的 position + 1 的數(shù)據(jù),所以我們只要在外部調(diào)用 Handler 的 sendMessage() 方法,就能使 ViewPager 進(jìn)行自動的無限輪播。
1.2 讓 ViewPager 從最后一張滑動到第一張
我們知道,ViewPager 是無法從最后一頁滑動到第一頁的,但我們可以換一個思路,如果我們在 ViewPager 的 Adapter 里面,通過 getCount() 方法將 ViewPager 的大小設(shè)置為無限大,然后通過取余的方式來保證滑動的頁面一直對應(yīng)數(shù)據(jù)源的那幾個數(shù)據(jù),這樣便能讓 ViewPager 實現(xiàn)從最后一張滑動到第一張的效果。
public int getCount() {
if (mBannerList == null) {
return 0;
}
if (mBannerList.size() == 1) {
return 1;
} else {
return Integer.MAX_VALUE;
}
}
public Object instantiateItem(ViewGroup container, final int position) {
if (mBannerList != null && mBannerList.size() > 0) {
View imageView = null;
Uri uri = Uri.parse(mBannerList.get(position % mBannerList.size()).cover_url); // 通過取余的方式
imageView = new SimpleDraweeView(mContext);
((SimpleDraweeView) imageView).setImageURI(uri);
container.addView(imageView);
return imageView;
}
return null;
}
二、如何進(jìn)行優(yōu)化
在上面我們只是簡單的實現(xiàn)了 ViewPager 的自動輪播功能,但其實還有很多的細(xì)節(jié)需要我們進(jìn)行優(yōu)化,例如:我們是通過將 ViewPager 的大小設(shè)置為無限大的方式,來實現(xiàn)從最后一張滑動到第一張的,但這時候如果不進(jìn)行緩存的話,我們在 Adapter 的 instantiateItem(ViewGroup container, final int position) 方法里面,便需要返回很多新 new 出來的 View,這樣會造成不必要的內(nèi)存浪費(fèi),只有對這些細(xì)節(jié)進(jìn)行優(yōu)化,才能讓我們的控件更加的好用,穩(wěn)定性和性能方面也會更加優(yōu)異。
2.1 通過緩存減少內(nèi)存浪費(fèi)
為了讓 ViewPager 能實現(xiàn)無線輪播的功能,我們是使用了通過將 getCount() 的大小設(shè)置為無限大的方式來實現(xiàn)的,但這會產(chǎn)生一個問題,這樣會使我們在 Adapter 的 instantiateItem() 方法中返回很多新 new 出來的 View,而造成不必要的內(nèi)存浪費(fèi)。
所以我們可以通過一個 List 作為緩存池,在 Adapter 中的 destroyItem() 方法中將廢棄的 object 存到緩存池中,重復(fù)利用,這樣便能避免內(nèi)存浪費(fèi)。
private final ArrayList<View> mViewCaches = new ArrayList<>();
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
ImageView imageView = (ImageView) object;
container.removeView(imageView);
mViewCaches.add(imageView);
}
然后在 Adapter 的 instantiateItem() 方法中,從 List 中取出已經(jīng)被緩存的 View,進(jìn)行重復(fù)利用
public Object instantiateItem(ViewGroup container, final int position) {
if (mBannerList != null && mBannerList.size() > 0) {
View imageView = null;
Uri uri = Uri.parse(mBannerList.get(position % mBannerList.size()).cover_url);
if (mViewCaches.isEmpty()) {
imageView = new SimpleDraweeView(GlobalContext.getContext());
} else {
// 當(dāng)緩存集合有數(shù)據(jù)時,進(jìn)行復(fù)用
imageView = (ImageView) mViewCaches.remove(0);
}
}
2.2 適當(dāng)?shù)耐V棺詣虞啿?/strong>
當(dāng)我們觸摸 Banner 或者離開當(dāng)前展示 Banner 的頁面時,如果 banner 還在不停的進(jìn)行無線輪播的話,會造成沒必要的性能損失,所以我們需要在觸摸 Banner 以及當(dāng)前的 Activity 為不可見狀態(tài)的時候,停止 Banner 的輪播,從而提升性能。
public boolean dispatchTouchEvent(MotionEvent ev) {
int action = ev.getAction();
if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL
|| action == MotionEvent.ACTION_OUTSIDE) {
startAutoPlay();
} else if (action == MotionEvent.ACTION_DOWN) {
stopAutoPlay();
}
return super.dispatchTouchEvent(ev);
}
2.3 改變 ViewPager 切換速度
原生的 ViewPager 在進(jìn)行自動輪播的時候,切換速度是特別快的,會給人一種很突兀的感覺,而且 ViewPager 也沒有提供接口給我們對 ViewPager 進(jìn)行切換速度的設(shè)置,所以我們需要通過反射的方式,使用 Scroller 來進(jìn)行切換速度的設(shè)置,從而讓我們的 Banner 更加的絲滑。
public AutoScrollViewPager(Context context) {
this(context, null);
initViewPagerScroll();
}
private void initViewPagerScroll() {
try {
Field mField = ViewPager.class.getDeclaredField("mScroller");
mField.setAccessible(true);
BannerScroller scroller = new BannerScroller(getContext());
mField.set(this, scroller);
} catch (Exception e) {
Log.d(TAG, e.getMessage());
}
}
public class BannerScroller extends Scroller {
private static final int BANNER_DURATION = 1000;
private int mDuration = BANNER_DURATION;
public BannerScroller(Context context) {
super(context);
}
@Override
public void startScroll(int startX, int startY, int dx, int dy, int duration) {
super.startScroll(startX, startY, dx, dy, mDuration);
}
}
至此,我們的自動輪播控件,無論是性能上還是穩(wěn)定性上都已經(jīng)很不錯了。
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
- Android實現(xiàn)圖片輪播效果的兩種方法
- Android實現(xiàn)圖片輪播效果
- Android實現(xiàn)Banner界面廣告圖片循環(huán)輪播(包括實現(xiàn)手動滑動循環(huán))
- Android 使用ViewPager自動滾動循環(huán)輪播效果
- Android實現(xiàn)圖片自動輪播并且支持手勢左右無限滑動
- Android使用ViewPager加載圖片和輪播視頻
- Android實現(xiàn)圖片文字輪播特效
- Android自動播放Banner圖片輪播效果
- Android實現(xiàn)廣告圖片輪播效果
- Android自定義控件實現(xiàn)簡單的輪播圖控件
相關(guān)文章
Android中ListView下拉刷新的實現(xiàn)代碼
這篇文章主要介紹了Android中ListView下拉刷新的實現(xiàn)代碼的相關(guān)資料,需要的朋友可以參考下2017-06-06
Android Glide圖片加載(加載監(jiān)聽、加載動畫)
這篇文章主要為大家詳細(xì)介紹了Android Glide圖片加載的具體實現(xiàn)方法,包括加載監(jiān)聽、加載動畫,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-11-11
21天學(xué)習(xí)android開發(fā)教程之SurfaceView與多線程的混搭
21天學(xué)習(xí)android開發(fā)教程之SurfaceView與多線程的混搭,感興趣的小伙伴們可以參考一下2016-02-02
Android AutoCompleteTextView自動提示文本框?qū)嵗a
這篇文章主要介紹了Android AutoCompleteTextView自動提示文本框?qū)嵗a的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2016-07-07
Android編程實現(xiàn)ListView滾動提示等待框功能示例
這篇文章主要介紹了Android編程實現(xiàn)ListView滾動提示等待框功能,結(jié)合實例形式分析了Android ListView滾動事件相關(guān)實現(xiàn)技巧,需要的朋友可以參考下2017-02-02

