您好,登錄后才能下訂單哦!
前言
在本文開始之前請大家先看一下這篇文章:https://www.jb51.net/article/113510.htm
上面的這篇文章是之前寫的,里面發(fā)現(xiàn)有很多不好用地方,也學(xué)到些新姿勢,改動了許多地方。下面來看看詳細(xì)的介紹:
要點:
1.可以通過后臺控制Item的展示.
2.TreeRecyclerAdapter,可以展開,折疊.多級展示
3.adapter可以使用裝飾者模式進(jìn)行擴(kuò)展.支持EmptyAdapter.可以添加headview和footview
4.item的樣式可以編寫文檔,type與Class進(jìn)行對應(yīng),實現(xiàn)后臺控置,相同Item復(fù)用.
思路:(包含第一篇的思路)
1.adapter應(yīng)該只需要關(guān)心List<baseItem> datas 的內(nèi)容
2.把每個item看成獨立的個體. 布局樣式,每行所占比,onbindViewHolder由各個item實現(xiàn)。
3.每一個item應(yīng)該只關(guān)心自己的數(shù)據(jù)和自己的下一級的數(shù)據(jù),不會去關(guān)心上上級,下下級
4.展開的實現(xiàn),點擊時item把子數(shù)據(jù)拿出來,然后添加到adapter的datas中,變成同級,因為只會展開自己的下級數(shù)據(jù)。
5.折疊的實現(xiàn),拿到下級數(shù)據(jù)(可以理解因為一個文件夾下文件),然后從adapter的datas中刪除這些數(shù)據(jù)。
6.后臺控制可以通過初始化注冊的方法,將Item的Class注冊.保存到集合里
7.后臺返回字段,獲取對應(yīng)class文件,通過Class.newInstance()
方法構(gòu)建實例.
8.將ViewHolder與Adapter寫成通用的,不需要再寫多個Adatper與ViewHolder,只需要寫多個Baseitem.與BaseItamData(JavaBean).
目錄介紹
+ 1.Adapter * Wapper------擴(kuò)展的wapper, * EmptyWapper --------當(dāng)無數(shù)據(jù)時顯示頁面. * HeaderAndFootWapper --------添加頭部view和尾部view - BaseRecyclerAdapter --------封裝的Adatper基類 - ItemManager --------接口,管理Adatper刷新,增刪操作 - TreeRecyclerAdapter ----多級列表,樹形結(jié)構(gòu)的adapter - TreeRecyclerViewType ----多級列表的顯示樣式,枚舉 - ViewHolder----封裝的通用viewHodler * 2.base BaseItem<D extends BaseItemData> ------item的封裝 BaseItemData-----item的數(shù)據(jù)要求.javabean需要繼承該類. * 3.factory ItemConfig ----添加item的class,配置樣式 Itemfactory----通過class生成BaseItem的工廠類 * 4.view TreeItem ----樹形列表的子item TreeItemGroup ----樹形列表的父item TreeParent---TreeItemGroup 實現(xiàn)該接口 TreeSelectItemGroup---可以選中子item的TreeItemGroup. demo:見購物頁面
來張丑丑的圖:
下面貼出部分代碼:
(一).BaseRecyclerAdapter :
/** * 普通BaseRecyclerAdapter,itme無父子關(guān)系. * 限定泛型為BaseItem的子類. * 通過BaseItem去處理ViewHolder */ public class BaseRecyclerAdapter<T extends BaseItem> extends RecyclerView.Adapter<ViewHolder> { private List<T> mDatas;//展示數(shù)據(jù) private ItemManager<T> mItemManager; private CheckItem mCheckItem; @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { //看源碼,這里的parent就是Recyclerview,所以不會為null.可以通過它拿到context return ViewHolder.createViewHolder(parent.getContext(), parent, viewType); } @Override public void onBindViewHolder(ViewHolder holder, int position) { T t = getDatas().get(position); //檢查是否綁定了ItemManage,因為item需要通過ItemManage告訴adapter刷新,增刪 checkItemManage(t); //具體onBindViewHolder放到item里面去實現(xiàn) t.onBindViewHolder(holder); //實現(xiàn)點擊事件 onBindViewHolderClick(holder); } /** * 實現(xiàn)item的點擊事件 * * @param holder 綁定點擊事件的ViewHolder */ public void onBindViewHolderClick(final ViewHolder holder) { //判斷當(dāng)前holder是否已經(jīng)設(shè)置了點擊事件 if (!holder.itemView.hasOnClickListeners()) { holder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //獲得holder的position int layoutPosition = holder.getLayoutPosition(); //檢查position是否可以點擊 if (getCheckItem().checkPosition(layoutPosition)) { //檢查并得到真實的position int itemPosition = getCheckItem().getAfterCheckingPosition(layoutPosition); //拿到對應(yīng)item,回調(diào). getDatas().get(itemPosition).onClick(); } } }); } } /** * 這里將LayoutId作為type,因為LayoutId不可能相同,個人覺得可以作為item的標(biāo)志 * @param position * @return */ @Override public int getItemViewType(int position) { return mDatas.get(position).getLayoutId(); } @Override public int getItemCount() { return mDatas == null ? 0 : mDatas.size(); } public List<T> getDatas() { if (mDatas == null) { mDatas = new ArrayList<>(); } return mDatas; } /** * 需要手動setDatas(List<T> datas),否則數(shù)據(jù)為空 * @param datas */ public void setDatas(List<T> datas) { if (datas != null) { mDatas = datas; getItemManager().notifyDataSetChanged(); } } }
(二).TreeRecyclerAdapter
/** * Created by baozi on 2017/4/20. * 樹級結(jié)構(gòu)recycleradapter. * item之間有子父級關(guān)系, */ public class TreeRecyclerAdapter<T extends TreeItem> extends BaseRecyclerAdapter<T> { private TreeRecyclerViewType type; /** * 最初的數(shù)據(jù).沒有經(jīng)過增刪操作. */ private List<T> initialDatas; @Override public void onBindViewHolderClick(final ViewHolder holder) { //判斷是否已有點擊監(jiān)聽 if (!holder.itemView.hasOnClickListeners()) { holder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //獲得holder的LayoutPosition. int layoutPosition = holder.getLayoutPosition(); //判斷是否需要點擊 if (getCheckItem().checkPosition(layoutPosition)) { int itemPosition = getCheckItem().getAfterCheckingPosition(layoutPosition); //展開,折疊和item點擊不應(yīng)該同時響應(yīng)事件. if (type != TreeRecyclerViewType.SHOW_ALL) { //展開,折疊 expandOrCollapse(itemPosition); } else { //點擊事件 T item = getDatas().get(itemPosition); TreeItemGroup itemParentItem = item.getParentItem(); //判斷上一級是否需要攔截這次事件,只處理當(dāng)前item的上級,不關(guān)心上上級如何處理. if (itemParentItem != null && itemParentItem.onInterceptClick(item)) { return; } item.onClick(); } } } }); } } @Override public void setDatas(List<T> datas) { //保存未修改過的List initialDatas = datas; //如果展開顯示全部,則需要遞歸處理添加所以的item if (type == TreeRecyclerViewType.SHOW_ALL) { for (int i = 0; i < datas.size(); i++) { T t = datas.get(i); getDatas().add(t); //判斷item是否是TreeItemGroup if (t instanceof TreeItemGroup) { List childs = ((TreeItemGroup) t).getAllChilds(); if (childs != null) { //添加到item的后面. getDatas().addAll(childs); } } } } else { super.setDatas(datas); } } /** * 相應(yīng)RecyclerView的點擊事件 展開或關(guān)閉某節(jié)點 * * @param position 觸發(fā)的條目 */ private void expandOrCollapse(int position) { T baseItem = getDatas().get(position); if (baseItem instanceof TreeItemGroup && ((TreeItemGroup) baseItem).isCanChangeExpand()) { TreeItemGroup treeParentItem = (TreeItemGroup) baseItem; boolean expand = treeParentItem.isExpand(); List<T> allChilds = treeParentItem.getAllChilds(); if (expand) { getDatas().removeAll(allChilds); treeParentItem.onCollapse(); treeParentItem.setExpand(false); } else { getDatas().addAll(position + 1, allChilds); treeParentItem.onExpand(); treeParentItem.setExpand(true); } getItemManager().notifyDataSetChanged(); } } }
(三).BaseItem(部分get.set代碼省略)
/** * Item的基類 */ public abstract class BaseItem<D extends BaseItemData> { /** * 當(dāng)前item的數(shù)據(jù) */ protected D data; /** * item在每行中的spansize * 默認(rèn)為0,如果為0則占滿一行 * * @return 所占值, 比如recyclerview的列數(shù)為6, item需要占一半寬度, 就設(shè)置3 */ private int spanSize; /** * 可以通過ItemManager ,操作adatper * @return */ private ItemManager mItemManager; public int getLayoutId() { if (initLayoutId() <= 0) { throw new Resources.NotFoundException("請設(shè)置布局Id"); } return initLayoutId(); } /** * 子類需要實現(xiàn)該方法,并返回item的布局id * * @return 返回布局id.如果返回0,則會拋出異常 */ protected abstract int initLayoutId(); /** * 抽象holder的綁定 */ public abstract void onBindViewHolder(ViewHolder viewHolder); /** * 當(dāng)前條目的點擊回調(diào) * 如果不需要點擊事件,則可以不復(fù)寫該方法. */ public void onClick() { }
(四).TreeItem
/** * 組合模式 * TreeRecyclerAdapter的item */ public abstract class TreeItem<D extends BaseItemData> extends BaseItem<D> { private TreeItemGroup parentItem; public void setParentItem(TreeItemGroup parentItem) { this.parentItem = parentItem; } /** * 獲取當(dāng)前item的父級 * * @return */ @Nullable public TreeItemGroup getParentItem() { return parentItem; } }
(五).TreeItemGroup
/** * Created by baozi on 2016/12/22. * 擁有子集 * 子集可以是parent,也可以是child */ public abstract class TreeItemGroup<D extends BaseItemData> extends TreeItem<D> implements TreeParent { /** * 持有的子item */ private List<? extends BaseItem> childs; /** * 是否展開 */ private boolean isExpand; /** * 能否展開 */ protected boolean isCanChangeExpand = true; /** * 展開 */ @Override public void onExpand() { } /** * 折疊 */ @Override public void onCollapse() { } /** * 獲得自己的childs. * @return */ @Nullable public List<? extends BaseItem> getChilds() { return childs; } /** * 獲得所有childs,包括子item的childs * @return */ @Nullable public List<? extends BaseItem> getAllChilds() { if (getChilds() == null) { return null; } ArrayList<BaseItem> baseItems = new ArrayList<>(); for (int i = 0; i < childs.size(); i++) { //下級 BaseItem baseItem = childs.get(i); baseItems.add(baseItem); //判斷是否還有下下級,并且處于expand的狀態(tài) if (baseItem instanceof TreeItemGroup && ((TreeItemGroup) baseItem).isExpand()) { //調(diào)用下級的getAllChilds遍歷,相當(dāng)于遞歸遍歷 List list = ((TreeItemGroup) baseItem).getAllChilds(); if (list != null && list.size() > 0) { baseItems.addAll(list); } } } return baseItems; } public int getChildsCount() { return childs == null ? 0 : childs.size(); } /** * 初始化子集 * * @param data * @return */ protected abstract List<? extends BaseItem> initChildsList(D data); /** * 是否消費child的click事件 * * @param child 具體click的item * @return 返回true代表消費此次事件,child不會走onclick(),返回false說明不消費此次事件,child依然會走onclick() */ public boolean onInterceptClick(TreeItem child) { return false; }
(六).TreeSelectItemGroup
/** * Created by baozi on 2016/12/22. * 可以選中子item的TreeItemGroup,點擊的item會保存起來.可以通過 getSelectItems()獲得選中item */ public abstract class TreeSelectItemGroup<D extends BaseItemData> extends TreeItemGroup<D> { /** * 選中的子item.只支持下一級,不支持下下級 */ private List<BaseItem> selectItems; public List<BaseItem> getSelectItems() { if (selectItems == null) { selectItems = new ArrayList<>(); } return selectItems; } /** * 是否有選中item, * @return */ public boolean isHaveCheck() { return !getSelectItems().isEmpty(); } @Override public boolean onInterceptClick(TreeItem child) { //單選 if (selectFlag() == SelectFlag.SINGLE_CHOICE) { //如果已經(jīng)有選中的,則替換 if (getSelectItems().size() != 0) { getSelectItems().set(0, child); } else { //沒有選中的則添加 getSelectItems().add(child); } } else { //判斷是否已添加. int index = getSelectItems().indexOf(child); if (index == -1) {//不存在則添加 getSelectItems().add(child); } else {//存在則刪除 getSelectItems().remove(index); } } return super.onInterceptClick(child); } /** * 必須指定選中樣式 * @return */ public abstract SelectFlag selectFlag(); /** * 決定TreeSelectItemGroup的選中樣式 */ public enum SelectFlag { /** * 單選 */ SINGLE_CHOICE, /** * 多選 */ MULTIPLE_CHOICE }
具體的使用實例效果:
1.購物頁面:
Demo中的代碼:
//拿到數(shù)據(jù) List<StoreBean> storeBean = initData(); //通過ItemFactory生成第一級Item,如果是通過后臺控制,則不需要傳Class //List<ShopTitileItem> itemList = ItemFactory.createItemList(storeBean); List<ShopTitileItem> itemList = ItemFactory.createItemList(storeBean, ShopTitileItem.class); //創(chuàng)建TreeRecyclerAdapter mAdapter = new TreeRecyclerAdapter<>(); //設(shè)置adapter的顯示樣式 mAdapter.setType(TreeRecyclerViewType.SHOW_ALL); //將數(shù)據(jù)設(shè)置到Adapter中 mAdapter.setDatas(itemList); //設(shè)置adapter mRecyclerView.setAdapter(mAdapter); /** * item的代碼 * Created by baozi on 2016/12/22. */ public class ShopTitileItem extends TreeSelectItemGroup<StoreBean> { @Override protected List<? extends BaseItem> initChildsList(StoreBean data) { return ItemFactory.createTreeItemList(data.getShopListBeen(), this); } @Override protected int initLayoutId() { return R.layout.item_shopcart_title; } @Override public void onBindViewHolder(ViewHolder holder) { holder.setChecked(R.id.cb_ischeck, isHaveCheck()); } @Override public void onClick() { if (!isHaveCheck()) { getSelectItems().clear(); getSelectItems().addAll(getChilds()); } else { getSelectItems().clear(); } int size = getChilds().size(); for (int i = 0; i < size; i++) { ShopListBean data = (ShopListBean) getChilds().get(i).getData(); data.setCheck(isHaveCheck()); } getItemManager().notifyDataSetChanged(); } @Override public SelectFlag selectFlag() { return SelectFlag.MULTIPLE_CHOICE; } @Override public boolean canExpandOrCollapse() { return false; }
2.多級列表
Demo中的代碼:
//拿到數(shù)據(jù) List<CityBean> cityBeen = initData(); //通過ItemFactory生成List<BaseItem> List<OneTreeItemParent> itemList = ItemFactory.createItemList(cityBeen); TreeRecyclerAdapter treeRecyclerAdapter = new TreeRecyclerAdapter(); //設(shè)置數(shù)據(jù) treeRecyclerAdapter.setDatas(itemList); recyclerView.setAdapter(treeRecyclerAdapter); /** *item的代碼 * Created by baozi on 2016/12/8. */ public class OneTreeItemParent extends TreeItemGroup<CityBean> { @Override public List<? extends TreeItem> initChildsList(CityBean data) { return ItemFactory.createTreeItemList(data.getCitys(), TwoTreeItemParent.class, this); } @Override public int initLayoutId() { return R.layout.itme_one; } @Override public void onBindViewHolder(ViewHolder holder) { holder.setText(R.id.tv_content, data.getProvinceName()); } @Override public boolean canExpandOrCollapse() { return false; } }
3.多種type的列表
總結(jié):
1.我覺得像購物車那種頁面挺復(fù)雜的,既然寫了多級列表,何不擴(kuò)展一個出來
2.RecyclerView的點擊事件,看了很多封裝,發(fā)現(xiàn)很多都是每次onBindViewHolder去重新設(shè)置一遍,感覺挺不好的.
3.我喜歡把數(shù)據(jù)集合讓Adatper去持有,然后通過Adapter進(jìn)行增刪改查操作.直接在Activity里持有數(shù)據(jù)集合進(jìn)行操作,我不是習(xí)慣(- -)
4.用的習(xí)慣沒bug的才是好東西,如果你覺得實用或者能學(xué)到姿勢,就點個贊把,哈哈.
5.大部分的邏輯都在Item中,由于拆分開了,會發(fā)現(xiàn)每個item的代碼也不會很多
6.多級列表我已經(jīng)用在某個項目里了(- -),還沒發(fā)現(xiàn)什么問題(多級列表的簡單使用- -)
下面附上Demo.詳細(xì)代碼
github傳送門:TreeRecyclerView
本地下載:http://xiazai.jb51.net/201705/yuanma/TreeRecyclerView(jb51.net).rar
好了,以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對億速云的支持。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。