輪播圖框架確實有些爛大街了,實現原理也比較簡單,但在快速集成實現和可定製化上又有着不可調和的矛盾,有些框架集成容易,但卻可能會由於沒法作到足夠的自由定製化而沒法知足咱們的需求,而有些框架功能至關豐富,但卻十分臃腫,加個框架整個程序大了好幾兆,十分無奈。git
最近新接了一個項目,要求以下圖所示的複雜佈局Banner一份,而App的內部詳情頁還有一個簡單無需客製化佈局純圖片的Banner,這就讓我在框架的選擇上有些頭疼了,畢竟手頭已有的Banner框架並無合適的。 github
因而就忽然萌生本身寫一個的想法了,想搞一個不那麼大,又能知足需求的Banner,輪播圖的原理很簡單,基本就是首尾拼接尾首的Viewpager,而後在用戶滑動到最首或最尾的一頁時瞬間不帶動畫切換到尾或首頁,以實現「無線循環」的效果,具體代碼以下:bash
addItem(imageUrls.get(imageUrls.size() - 1)); //先添加一個尾部的圖
for (String url : imageUrls) { //正常添加全部的輪播圖
addItem(url);
}
addItem(imageUrls.get(0)); //最後添加第一頁的圖
複製代碼
考慮到快速實現自定義Banner佈局以及綁定自定義佈局中的組件,並實現相應的自定義內容,我嘗試使用了一個接口來實現。BindView接口容許傳入一個泛型用於肯定輪播圖用到的數據類型,通常能夠是Map,也能夠是自定義的Bean,然後在執行時會將生成好的根佈局rootView回傳出去,用戶能夠根據rootView.findViewById(resId)來實現組件的綁定,以及事件的設置:框架
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);
}
}
複製代碼
如上基本就完成了輪播圖組件的主體部分,剩下的也就是自動輪播、指示器和屬性設置,詳情能夠前往Github開源庫查看。動畫
另外重點來講一下對於普通Banner如何實現的問題,相比於上邊的自定義佈局Banner,普通Banner反而要更難,爲何呢?緣由在於自定義佈局Banner的子界面佈局是用戶本身去設計和定義的,存放在資源layout中,咱們繞過了用戶會使用什麼圖片顯示框架這一個問題,即,用戶可能用ImageView來實現圖片顯示,也可能會使用Fresco的SimpleDraweeView來實現圖片的顯示,而在普通Banner中,咱們要實例化的佈局直接就是用戶所要用的圖片顯示框架,但這對於Banner來講是未知的。ui
反覆思考後我決定用依然泛型來實現此功能,在普通Banner的BindView中給出一個泛型用於設置圖片顯示組件的類型,而後在Banner建立時將其實例化,添加到viewpager中,那麼重點難題就是如何將泛型實例化。url
泛型之因此爲「泛型」,即不肯定類型,不肯定類型就基本沒法實例化對象了,因此這裏須要繞一步來實現。在SimpleBanner中,我嘗試將接口BindView改變爲了抽象類BindData,在其中實現了一個方法用來實現泛型的實例化:spa
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的初始化方法至少須要一個參數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);
}
}
複製代碼
建立對象V後就能夠顯示到viewpager裏了,至此SimpleBanner最難的地方基本也就攻克了。
FastBanner提供兩個組件,即SimpleBanner用於快速實現普通輪播圖,而CustomBanner用於快速實現自定義佈局的輪播圖,僅須要簡單配置便可知足絕大多數須要使用輪播圖的場景。
實際使用方式以及說明,請移駕 Github 查看。
有任何疑問或建議歡迎在 Github.issues 頁面提交,也歡迎Star&Fork
寫文章不易,若是以爲好還勞煩點個贊吧!