前言
輪播圖框架確實有些爛大街了,實現(xiàn)原理也比較簡單瞻润,但在快速集成實現(xiàn)和可定制化上又有著不可調(diào)和的矛盾,有些框架集成容易,但卻可能會因為無法做到足夠的自由定制化而無法滿足我們的需求庭呜,而有些框架功能相當(dāng)豐富,但卻十分臃腫犀忱,加個框架整個程序大了好幾兆募谎,十分無奈。
最近新接了一個項目阴汇,要求如下圖所示的復(fù)雜布局Banner一份数冬,而App的內(nèi)部詳情頁還有一個簡單無需客制化布局純圖片的Banner,這就讓我在框架的選擇上有些頭疼了搀庶,畢竟手頭已有的Banner框架并沒有合適的拐纱。
自定義布局的CustomBanner
于是就突然萌生自己寫一個的想法了,想搞一個不那么大哥倔,又能滿足需求的Banner秸架,輪播圖的原理很簡單,基本就是首尾拼接尾首的Viewpager咆蒿,然后在用戶滑動到最首或最尾的一頁時瞬間不帶動畫切換到尾或首頁东抹,以實現(xiàn)“無線循環(huán)”的效果蚂子,具體代碼如下:
addItem(imageUrls.get(imageUrls.size() - 1)); //先添加一個尾部的圖
for (String url : imageUrls) { //正常添加所有的輪播圖
addItem(url);
}
addItem(imageUrls.get(0)); //最后添加第一頁的圖
考慮到快速實現(xiàn)自定義Banner布局以及綁定自定義布局中的組件,并實現(xiàn)相應(yīng)的自定義內(nèi)容缭黔,我嘗試使用了一個接口來實現(xiàn)食茎。BindView接口允許傳入一個泛型用于確定輪播圖用到的數(shù)據(jù)類型,一般可以是Map馏谨,也可以是自定義的Bean别渔,而后在執(zhí)行時會將生成好的根布局rootView回傳出去,用戶可以根據(jù)rootView.findViewById(resId)來實現(xiàn)組件的綁定田巴,以及事件的設(shè)置:
public interface BindView<D> {
void bind(D data, View rootView);
}
addItem方法的代碼如下:
private void addItem(D data) {
View item = LayoutInflater.from(context).inflate(customLayoutResId, null, false);
if (item != null) {
bindView.bind(data, item);
views.add(item);
}
}
如上基本就完成了輪播圖組件的主體部分钠糊,剩下的也就是自動輪播、指示器和屬性設(shè)置壹哺,詳情可以前往Github開源庫查看抄伍。
快速簡單的SimpleBanner
另外重點來說一下對于普通Banner如何實現(xiàn)的問題,相比于上邊的自定義布局Banner管宵,普通Banner反而要更難截珍,為什么呢?原因在于自定義布局Banner的子界面布局是用戶自己去設(shè)計和定義的箩朴,存放在資源layout中岗喉,我們繞過了用戶會使用什么圖片顯示框架這一個問題,即炸庞,用戶可能用ImageView來實現(xiàn)圖片顯示钱床,也可能會使用Fresco的SimpleDraweeView來實現(xiàn)圖片的顯示,而在普通Banner中埠居,我們要實例化的布局直接就是用戶所要用的圖片顯示框架查牌,但這對于Banner來說是未知的。
反復(fù)思考后我決定用依然泛型來實現(xiàn)此功能滥壕,在普通Banner的BindView中給出一個泛型用于設(shè)置圖片顯示組件的類型纸颜,然后在Banner創(chuàng)建時將其實例化,添加到viewpager中绎橘,那么重點難題就是如何將泛型實例化胁孙。
泛型之所以為“泛型”,即不確定類型称鳞,不確定類型就基本無法實例化對象了涮较,所以這里需要繞一步來實現(xiàn)。在SimpleBanner中胡岔,我嘗試將接口BindView改變?yōu)榱顺橄箢怋indData法希,在其中實現(xiàn)了一個方法用來實現(xiàn)泛型的實例化:
public abstract static class BindData<V> {
public abstract void bind(String url, V imageView);
public Class<V> getEntityClass() {
Type type = getClass().getGenericSuperclass();
ParameterizedType pType = (ParameterizedType) type;
Type[] params = pType.getActualTypeArguments();
@SuppressWarnings("unchecked")
Class<V> c = (Class<V>) params[0];
return c;
}
}
嘗試實例化V,并將其添加至viewpager靶瘸,這里需要助于的是對象V的初始化方法至少需要一個參數(shù)context苫亦,是不可以直接class.newInstance()的:
private void addItem(String url) {
V item;
try {
Constructor con = bindData.getEntityClass().getConstructor(Context.class);
item = (V) con.newInstance(context);
} catch (Exception e) {
e.printStackTrace();
return;
}
if (item != null) {
bindData.bind(url, item);
views.add(item);
}
}
創(chuàng)建對象V后就可以顯示到viewpager里了,至此SimpleBanner最難的地方基本也就攻克了怨咪。
總結(jié)
FastBanner提供兩個組件屋剑,即SimpleBanner用于快速實現(xiàn)普通輪播圖,而CustomBanner用于快速實現(xiàn)自定義布局的輪播圖诗眨,僅需要簡單配置即可滿足絕大多數(shù)需要使用輪播圖的場景唉匾。
實際使用方式以及說明,請移駕 Github 查看匠楚。
有任何疑問或建議歡迎在 Github.issues 頁面提交巍膘,也歡迎Star&Fork
寫文章不易,如果覺得好還勞煩點個贊吧芋簿!