最近看UI再設(shè)計(jì)新的APP效果圖荷并,發(fā)現(xiàn)首頁使用了類似京東首頁京東日?qǐng)?bào)模塊類似的廣告自動(dòng)滾動(dòng)效果合砂,于是就想著提前準(zhǔn)備,寫個(gè)通用組件源织。網(wǎng)上查閱了很多的文章翩伪,絕大多數(shù)都是說使用TextSwitcher來實(shí)現(xiàn)這個(gè)效果。我也用TextSwitcher實(shí)踐了一下谈息,確實(shí)能實(shí)現(xiàn)幻工,然后也很簡單只需要給TextSwitcher設(shè)置inAnimation(進(jìn)入動(dòng)畫),outAnimation(離開動(dòng)畫),factory(在他的makeView中生成View)黎茎,然后需要一個(gè)Handler定時(shí)切換即可完成囊颅,不理解的同學(xué)可以去看一下TextSwitcher的用法。
但是傅瞻,無意間踢代,發(fā)現(xiàn)淘寶首頁也有這么一個(gè)功能,叫淘寶頭條嗅骄,雖然說都是廣告的上下滾動(dòng)胳挎,但是淘寶頭條的內(nèi)容還有有區(qū)別的,他包含了兩條文本廣告信息溺森,以及一張圖片慕爬。
此時(shí),這樣子的需求,使用TextSwitcher是無法滿足我們的需求了屏积,原因很簡單医窿,TextSwitcher中的子View是由我們?cè)O(shè)置的Factory的makeView方法創(chuàng)建的,而這個(gè)方法返回的炊林,必須是TextView對(duì)象姥卢,這一點(diǎn)再TextSwitcher的源碼中可以證實(shí).
@Override
public void addView(View child, int index, ViewGroup.LayoutParams params) {
if (!(child instanceof TextView)) {
throw new IllegalArgumentException(
"TextSwitcher children must be instances of TextView");
}
super.addView(child, index, params);
}
其實(shí),android SDK中不僅僅提供了用于文本滾動(dòng)的TextSwitcher渣聚,同時(shí)還提供了用于圖片滾動(dòng)的ImageSwitcher独榴,但是他們都無法滿足我們的需求,因此奕枝,就尋思著是否可以有一個(gè)自定義布局的組件棺榔,來實(shí)現(xiàn)這個(gè)功能呢,這時(shí)候我查閱了一下TextSwitcher與ImageSwitcher,發(fā)現(xiàn)他們都是ViewSwitcher的子類隘道,那就通過一個(gè)集成ViewSwitcher來實(shí)現(xiàn)我們的需求吧症歇。
廢話不多說捞烟,先把效果圖拿上來(似乎已經(jīng)扯了很多廢話了。当船。题画。)
整個(gè)流程其實(shí)很簡單,我們只需要將一開始講述的幾點(diǎn)封裝到我們的Switcher中就可以了德频,首先我們定義一個(gè)Adapter,讓他作為數(shù)據(jù)與Switcher之間的橋梁苍息,同時(shí),這邊使用了泛型壹置,讓我們使用過程中更加靈活
public interface IAdvertAdapter<T> {
/**
* 獲取當(dāng)前數(shù)據(jù)個(gè)數(shù)
* @return
*/
public int getCount();
/**
* 獲取position位置對(duì)應(yīng)的數(shù)據(jù)
* @param position
* @return
*/
public T getItem(int position);
/**
* 創(chuàng)建View
* 這邊僅僅是創(chuàng)建View竞思,不要給View綁定數(shù)據(jù),或者添加事件監(jiān)聽之類
* Only new View or inflate layout
* @return
*/
public View makeView();
/**
* 為View綁定數(shù)據(jù)钞护,同時(shí)添加對(duì)應(yīng)的事件監(jiān)聽
* @param view
* @param data
*/
public void bindView(View view, T data);
}
然后盖喷,重點(diǎn)來了,創(chuàng)建我們的組件难咕,繼承ViewSwitcher,同時(shí)也實(shí)現(xiàn)ViewSwitcher.ViewFactory接口课梳,該類中其實(shí)也沒有太多動(dòng)心,就不貼出來了余佃,下面會(huì)給出源碼地址暮刃,比較核心的還是Handler,實(shí)現(xiàn)自動(dòng)輪播爆土,定時(shí)發(fā)送一條消息椭懊,然后調(diào)用ViewSwitcher的showNext()方法,就能實(shí)現(xiàn)自動(dòng)輪播功能了步势。
private class ScrollHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case FLAG_START_SCROLL:
View view = getNextView();
mAdapter.bindView(view, mAdapter.getItem(currentIndex));
Log.e(TAG, "Index:" + currentIndex + " //" + mAdapter.getItem(currentIndex).toString());
showNext();
currentIndex = ++currentIndex % mAdapter.getCount();
mHandler.sendEmptyMessageDelayed(FLAG_START_SCROLL, mTimeSpan);
break;
case FLAG_STOP_SCROLL:
mHandler.removeMessages(FLAG_START_SCROLL);
break;
case FLAG_REFRESH:
currentIndex = 0;
removeAllViews();
start();
break;
}
}
}
使用起來也非常簡單氧猬,類似與列表的使用,分一下幾步走
1.實(shí)現(xiàn)IAdvertAdapter,關(guān)鍵實(shí)現(xiàn)makeView(),再這個(gè)方法中加載我們自定義的布局坏瘩,或者自己創(chuàng)建的View盅抚,當(dāng)然,這邊不要去做數(shù)據(jù)綁定相關(guān)的操作桑腮。
2.實(shí)現(xiàn)IAdvertAdapter中的bindView泉哈,做一下數(shù)據(jù)綁定,事件綁定相關(guān)的操作
3.switchers.setAdapter(new IAdvertAdapter(context, data));
這邊只是寫了大體的使用步驟破讨,具體還是看源碼吧,非常簡單奕纫,喜歡的加伙伴可以幫忙加一個(gè)小星星提陶,算是一點(diǎn)鼓勵(lì)吧_
https://github.com/yunzhouhua/AdvertSwitcher
疑問
1.如果廣告很多創(chuàng)建了很多的View,而最終也就顯示兩個(gè)匹层,是否浪費(fèi)性能隙笆?有優(yōu)化嘛锌蓄?
? 開始我就有這樣的疑問,以為makeView每次都會(huì)創(chuàng)建新的View添加帶ViewSwitcher中撑柔,也準(zhǔn)備做一下View復(fù)用瘸爽,但是看了ViewSwitcher的源碼后,發(fā)現(xiàn)多費(fèi)心了铅忿,google爸爸早就幫我們想到了剪决。ViewSwitcher中只會(huì)有兩個(gè)View,makeView也只會(huì)調(diào)用兩次檀训,如果有第三次的情況柑潦,程序肯定會(huì)奔潰,不信嘛峻凫?看下下面的代碼渗鬼,ViewSwitcher-addView
@Override
public void addView(View child, int index, ViewGroup.LayoutParams params) {
if (getChildCount() >= 2) {
throw new IllegalStateException("Can't add more than 2 views to a ViewSwitcher");
}
super.addView(child, index, params);
}
ViewSwitcher內(nèi)部再setFactory的時(shí)候連續(xù)調(diào)用了兩次obtainView創(chuàng)建出了對(duì)應(yīng)的View并添加到ViewSwitcher,而之后的滾動(dòng)效果完全就是這兩個(gè)view通過動(dòng)畫荧琼,控制顯示/隱藏實(shí)現(xiàn)的譬胎。感興趣的可以看一下源碼。