Android 復雜的多類型列表視圖新寫法:MultiType
MultiType
Android 復雜的多類型列表視圖新寫法,清晰、靈活、模塊開發、插件化思想
這幾天晚上回家開始設計我的 TimeMachine 的消息池系統,并抽取出來開源成一個全新的類庫: MultiType! 從前,我們寫一個復雜的、多 item view types 的列表視圖,經常要做一堆繁瑣的工作,而且不小心的話代碼還堆積嚴重:我們需要覆寫 RecyclerView.Adapter 的 getItemViewType 方法,并新增一些 type 整形常量,而且 ViewHolder 繼承、泛型傳遞、轉型也比較糟糕,畢竟 Adapter 只能接受一個泛型……十分麻煩導致過于復雜的頁面經常會使用 ScrollView 來實現,一次性加載,而且失去了復用性。
而且,一旦我們需要新增一些新的 item view types ,就得去修改 Adapter 舊的代碼,步驟繁多,侵入較強。
現在好了,只要三步,不需要修改舊代碼,只要無腦往池子里插入新的 type ,會自動連接、分發數據和事件,新增再多的 item types 都能輕松搞定,支持 RV 、復用,代碼模塊開發,清晰而靈活。若要說為什么這么靈活? 因為它本來就是為 IM 視圖開發的,想想 IM 的消息類型可能有多少種而且新增頻繁。
接入
在你的 build.gradle :
dependencies {
compile 'me.drakeet.multitype:multitype:1.1-beta2'
}
使用
Step 1. 創建一個 classimplements ItemContent ,它將是你的數據類型或 Java bean ,示例:
public class TextItemContent implements ItemContent, Savable {
@NonNull public String text;
public TextItemContent(@NonNull String text) {
this.text = text;
}
public TextItemContent(@NonNull byte[] data) {
init(data);
}
@Override public void init(@NonNull byte[] data) {
String json = new String(data);
this.text = new Gson().fromJson(json, TextItemContent.class).text;
}
@NonNull @Override public byte[] toBytes() {
return new Gson().toJson(this).getBytes();
}
}</code></pre>
Step 2. 創建一個 class 繼承 ItemViewProvider<T extends ItemContent> ,示例:
public class TextItemViewProvider extends ItemViewProvider<TextItemContent> {
private static class ViewHolder extends ItemViewProvider.ViewHolder {
@NonNull final TextView text;
ViewHolder(@NonNull View itemView) {
super(itemView);
this.text = (TextView) itemView.findViewById(R.id.text);
}
}
@NonNull @Override
protected View onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) {
View root = inflater.inflate(R.layout.item_text, parent, false);
ViewHolder holder = new ViewHolder(root);
root.setTag(holder);
return root;
}
@Override
protected void onBindView(
@NonNull View view, @NonNull TextItemContent content, @NonNull TypeItem typeItem) {
ViewHolder holder = (ViewHolder) view.getTag();
holder.text.setText("hello: " + content.text);
}
}</code></pre>
Step 3. 好了,你不必再創建新的類文件了,只要往你的 Activity 中加入 RecyclerView 和 List<TypeItem> 即可,示例:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = (RecyclerView) findViewById(R.id.list);
itemFactory = new TypeItemFactory.Builder().build();
TypeItem textItem = itemFactory.newItem(new TextItemContent("world"));
TypeItem imageItem = itemFactory.newItem(new ImageItemContent(R.mipmap.ic_launcher));
TypeItem richItem = itemFactory.newItem(new RichItemContent("小艾大人賽高", R.mipmap.avatar));
List<TypeItem> typeItems = new ArrayList<>(80);
for (int i = 0; i < 20; i++) {
typeItems.add(textItem);
typeItems.add(imageItem);
typeItems.add(richItem);
}
/* register the types before setAdapter, that's all right */
ItemTypePool.register(TextItemContent.class, new TextItemViewProvider());
ItemTypePool.register(ImageItemContent.class, new ImageItemViewProvider());
ItemTypePool.register(RichItemContent.class, new RichItemViewProvider());
recyclerView.setAdapter(new TypeItemsAdapter(typeItems));
}</code></pre>
大功告成!
你可以閱讀源碼項目中的 sample 模塊獲得更多信息和示例,當完整的示例代碼運行起來,它是這樣子的:

題外話
這個類庫成品看來是挺精巧的,或者說輕巧,但一個人從無到有把它設計和創造出來,還是費了很多思考和多次推翻重構,其中有些點看起來可能自然而然,但是它在開發過程中可能都是一個小坎,如果沒有找到合適的結構或設計,整體可能就不能搭建起來,使用也可能沒那么簡單和靈活。所以,要是有人感興趣,之后可以分享一下開發過程中遇到的問題和思考,還是很有意思的 : )
來自:https://drakeet.me/multitype