非約束列表,
也是不少同窗口中的「萬能適配器」,
不過我並不認同「萬能」的這個說法,
誰的適配器ListView和RecyclerView通用?git
預覽一下效果先:
一、單列列表
github
二、多列列表
dom
三、混合列表
ide
顯然,
從界面上看不出什麼名堂,
那就先說下個人非約束列表有什麼優點吧。this
打個比方,
某中學要給10臺電腦升級程序,
平均一臺電腦操做一次須要一個小時。spa
初中生可能會操做10次,
耗時10小時。.net
高中生可能會把全部電腦連起來,
同時操控,
只須要操做一次,
耗時一個小時。code
咱們用普通的Adapter的話,
就比如初中生,
每次修改一個條目,
就把全部使用這個條目的類全改一遍,
不管是Activity仍是Adapter,
可是用了非約束列表就不同了,
邏輯基本上都在Bean裏,
基本上只須要改itemLayout的樣式,
和Bean裏的邏輯便可。blog
到這裏,
可能有同窗會疑惑,
爲何無論Adapter?
由於,
個人項目只須要一個Adapter,
一個Adapter,
全場通用!繼承
說得細一點,
就是我把邏輯所有拆散重組,
Adapter架空,
只負責Activity、ViewHolder、bean之間的連通。
我我的喜歡把View和與其相對應的數據放一塊兒,
因此我把ViewHolder和邏輯放到了Bean裏,
經過一個接口來使二者進行結合,
哦不,
是將數據顯示到View上。
可是,
ViewHolder那麼多,
Adapter怎麼將其連通起來呢?
因此我寫了一個ViewHolderManager,
ViewHolderManager負責根據條目的類型,
找到相對應的ViewHolder,
進行實例化並返回給Adapter。
總體流程以下圖:
好了,
原理就說到這裏,
━━━━━━━━━━━━━━━這是清理內存的分割線━━━━━━━━━━━━━━━
下面開始聊聊個人非約束列表的使用步驟:
一:
新建一個Bean類,
裏邊寫個ViewHolder內部類,
繼承ViewHolderManager.ViewHolder,
和普通的Adapter的內部類差很少,
不過須要注意的是,
構造裏的參數不同:
/** * ViewHolder --> 主頁的按鈕 */ public static class MusicViewHolder extends ViewHolderManager.ViewHolder { public RelativeLayout rl_music; public TextView tv_song; public TextView tv_singer; public MusicViewHolder(ViewGroup viewGroup) { // 兩個參數,第一個viewGroup不解釋,第二個即本ViewHolder對應的LayoutXml super(viewGroup, R.layout.item_music); rl_music = (RelativeLayout) itemView.findViewById(R.id.rl_music); tv_song = (TextView) itemView.findViewById(R.id.tv_song); tv_singer = (TextView) itemView.findViewById(R.id.tv_singer); } }
不難發現,
構造裏多了個參數,
即該ViewHolder對應的LayoutXml.
二:
進入ViewHolderManager,
對應你新寫的ViewHolder,
增長一個公開靜態常量,
只要不與其餘的值重複便可,
並put到itemMap裏,
key爲你剛寫的常量,
value爲剛寫的ViewHolder的class。
/** * 條目類型 --> …… */ public static final int //…… /** * 條目類型 --> 新聞卡片 */ public static final int ITEM_TYPE_NEWS = 8; /** * 條目類型 --> 音樂 */ public static final int ITEM_TYPE_MUSIC = 9; /** * 加載條目類型,以及對應的條目XML */ static { itemMap = new HashMap<>(); …… itemMap.put(ITEM_TYPE_NEWS, BeanNews.NewsViewHolder.class); itemMap.put(ITEM_TYPE_MUSIC, BeanMusic.MusicViewHolder.class); }
三:
回到剛纔寫的Bean,
繼承FreedomBean,
在initItemType()裏,
set一下剛在ViewHolderManager裏定義的那個常量,
@Override protected void initItemType() { setItemType(ViewHolderManager.ITEM_TYPE_MUSIC); }
在initBindView()裏,
把普通Adapter裏onBindViewHolder()的代碼挪過來。
@Override protected void initBindView(final List list) { setViewHolderBindListener(new ViewHolderBindListener() { @Override public void onBindViewHolder(final Activity activity, final ViewHolderManager.ViewHolder viewHolder, final int position) { final MusicViewHolder vh = (MusicViewHolder) viewHolder; final BeanMusic bean = (BeanMusic) list.get(position); vh.tv_song.setText(bean.getSong()); vh.tv_singer.setText(bean.getSinger()); vh.rl_music.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { …… } }); } }); }
若是須要和Activity交互,
則Activity實現FreedomCallback接口,
並在onClickCallback裏編寫代碼,
而後回到Bean裏調用getCallback(activity).onClickCallback();
vh.rl_music.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 點擊事件 // 若是不須要和Activity進行交互, // 那麼直接在這裏寫點擊事件便可 // // 若是須要和Activity進行交互, // 那麼Activity實現FreedomCallback接口, // 並在onClickCallback裏編寫代碼, // 便可觸發回調, // 以和Activity進行交互。 // // 注意: // 該Activity必須實現FreedomCallback接口才能觸發回調, // 不然會報錯 getCallback(activity).onClickCallback(v, position, vh); } });
例:
類BeanMusic裏initBindView方法裏的vh.rl_music.setOnClickListener()。
好了,
Bean就完成了,
Activity裏使用它的方式和普通的沒什麼差異,
只是聲明數據源mList的時候,
類型爲Object或者不要加類型就好:
/** * 數據源 */ private List mList;
而後就可使用FreedomAdapter了:
// 實例化RecyclerView mAdapter = new FreedomAdapter(this, mList); recycler.setLayoutManager(new LinearLayoutManager(this)); recycler.setItemAnimator(new DefaultItemAnimator()); recycler.setAdapter(mAdapter);
使用起來雖然沒有比普通的簡單太多,
但也功能要比普通的強大太多啊不是麼?
代碼很簡單,
註釋我也寫得很全,
若是仍是有疑問的地方,
歡迎在文章下評論,
或者加入QQ討論羣:569614530,
羣裏找我,
我是塵少。
本文github連接:
https://github.com/Bamboy1203...
也能夠先下載apk安裝體驗: