国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

Android中RecyclerView實現多級折疊列表效果(TreeRecyclerView)

2019-10-23 18:29:10
字體:
來源:轉載
供稿:網友

前言

首先不得不吐槽一下產品,尼瑪為啥要搞這樣的功能....搞個兩級的不就好了嘛...自帶控件,多好。三級,四級,聽說還有六級的....這樣喪心病狂的設計,后臺也不好給數據吧。

先看看效果:

兩級的效果:

recyclerview多級列表,recyclerview二級列表,recyclerview折疊效果

三級的效果:

recyclerview多級列表,recyclerview二級列表,recyclerview折疊效果

全部展開的效果(我只寫了五級)

recyclerview多級列表,recyclerview二級列表,recyclerview折疊效果

說說為什么寫這貨吧:

公司產品提出三級這個需求后,我就在網上找啊找.

找的第一個,發現實現其實是ExpandListview嵌套.

找的第二個,ExpandRecyclview,然后就用唄,發現三級展開很卡,看源碼,

發現是RecyclerView套RecyclerView

就沒有不嵌套的么.....

然后找到hongyang的那個博客,寫個試試吧.

說說思路:

      1.Treeadapter應該只需要關心List<TreeAdapterItem> datas 的內容

      2.把每個item看成獨立的個體,布局樣式,每行所占比,bindViewHolder都由自己的來決定。

      3.每一個item應該只關心自己的數據和自己的下一級的數據,不會去關心上上級,下下級

      4.展開的實現,item把子數據集拿出來,然后添加到List<TreeAdapterItem> datas,變成與自己同級,因為每次展開只會展開一級數據。

      5.折疊遞歸遍歷所有子數據,遞歸拿到自己所有的子數據集(可以理解因為一個文件夾下所有的文件,包括子文件夾下的所有),然后從List<TreeAdapterItem> datas刪除這些數據。

見代碼:

/** * Created by Jlanglang on 2016/12/7.* */public abstract class TreeAdapterItem<D> { /** * 當前item的數據 */ protected D data; /** * 持有的子數據 */ protected List<TreeAdapterItem> childs; /** * 是否展開 */ protected boolean isExpand; /** * 布局資源id */ protected int layoutId; /** * 在每行中所占的比例 */ protected int spanSize; ···· get/set方法省略。。。。 ···· public TreeAdapterItem(D data) { this.data = data; childs = initChildsList(data); layoutId = initLayoutId(); spanSize = initSpansize(); } /** * 展開 */ public void onExpand() { isExpand = true; } /** * 折疊 */ public void onCollapse() { isExpand = false; } /** * 遞歸遍歷所有的子數據,包括子數據的子數據 * * @return List<TreeAdapterItem> */ public List<TreeAdapterItem> getAllChilds() {  ArrayList<TreeAdapterItem> treeAdapterItems = new ArrayList<>();  for (int i = 0; i < childs.size(); i++) {  TreeAdapterItem treeAdapterItem = childs.get(i);  treeAdapterItems.add(treeAdapterItem);  if (treeAdapterItem.isParent()) {   List list = treeAdapterItem.getAllChilds();   if (list != null && list.size() > 0) {   treeAdapterItems.addAll(list);   }  }  }  return treeAdapterItems; } /** * 是否持有子數據 * * @return */ public boolean isParent() {  return childs != null && childs.size() > 0; } /** * item在每行中的spansize * 默認為0,如果為0則占滿一行 * 不建議連續的兩級,都設置該數值 * * @return 所占值 */ public int initSpansize() {  return spanSize; } /** * 初始化子數據 * * @param data * @return */ protected abstract List<TreeAdapterItem> initChildsList(D data); /** * 該條目的布局id * * @return 布局id */ protected abstract int initLayoutId(); /** * 抽象holder的綁定 * * @param holder ViewHolder */ public abstract void onBindViewHolder(ViewHolder holder);}

再來看看Adapter

public class TreeRecyclerViewAdapter<T extends TreeAdapterItem> extends RecyclerView.Adapter<ViewHolder> { protected Context mContext; /** * 存儲所有可見的Node */ protected List<T> mDatas;//處理后的展示數據 /** * 點擊item的回調接口 */ private OnTreeItemClickListener onTreeItemClickListener; public void setOnTreeItemClickListener(OnTreeItemClickListener onTreeItemClickListener) { this.onTreeItemClickListener = onTreeItemClickListener; } /** * * @param context 上下文 * @param datas 條目數據 */ public TreeRecyclerViewAdapter(Context context, List<T> datas) { mContext = context; mDatas = datas; } /** * 相應RecyclerView的點擊事件 展開或關閉 * 重要 * @param position 觸發的條目 */ public void expandOrCollapse(int position) { //獲取當前點擊的條目 TreeAdapterItem treeAdapterItem = mDatas.get(position); //判斷點擊的條目有沒有下一級 if (!treeAdapterItem.isParent()) {  return; } //判斷是否展開 boolean expand = treeAdapterItem.isExpand(); if (expand) {  //獲取所有的子數據.  List allChilds = treeAdapterItem.getAllChilds();  mDatas.removeAll(allChilds);  //告訴item,折疊  treeAdapterItem.onCollapse(); } else {  //獲取下一級的數據  mDatas.addAll(position + 1, treeAdapterItem.getChilds());  //告訴item,展開  treeAdapterItem.onExpand(); } notifyDataSetChanged(); } //adapter綁定Recycleview后. @Override public void onAttachedToRecyclerView(RecyclerView recyclerView) { super.onAttachedToRecyclerView(recyclerView); //拿到布局管理器 RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager(); //判斷是否是GridLayoutManager,因為GridLayoutManager才能設置每個條目的行占比. if (layoutManager instanceof GridLayoutManager) {  final GridLayoutManager gridLayoutManager = (GridLayoutManager) layoutManager;  gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {  @Override  public int getSpanSize(int position) {   TreeAdapterItem treeAdapterItem = mDatas.get(position);   if (treeAdapterItem.getSpanSize() == 0) {   //如果是默認的大小,則占一行   return gridLayoutManager.getSpanCount();   }   //根據item的SpanSize來決定所占大小   return treeAdapterItem.getSpanSize();  }  }); } } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { //這里,直接通過item設置的id來創建Viewholder return ViewHolder.createViewHolder(mContext, parent, viewType); } @Override public void onBindViewHolder(ViewHolder holder, final int position) { final TreeAdapterItem treeAdapterItem = mDatas.get(position); holder.itemView.setOnClickListener(new View.OnClickListener() {  @Override  public void onClick(View v) {  //折疊或展開  expandOrCollapse(position);  if (onTreeItemClickListener != null) {   //點擊監聽的回調.一般不是最后一級,不需要處理吧.   onTreeItemClickListener.onClick(treeAdapterItem, position);  }  } }); treeAdapterItem.onBindViewHolder(holder); } @Override public int getItemViewType(int position) { //返回item的layoutId return mDatas.get(position).getLayoutId(); } @Override public int getItemCount() { return mDatas == null ? 0 : mDatas.size(); } public interface OnTreeItemClickListener { void onClick(TreeAdapterItem node, int position); }}

具體使用:

/** * Created by baozi on 2016/12/8. */public class OneItem extends TreeAdapterItem<CityBean> { public OneItem(CityBean data) { super(data); } //這里數據用的是,一個三級城市列表數據。 @Override protected List<TreeAdapterItem> initChildsList(CityBean data) {//這個CityBean 是一級數據 ArrayList<TreeAdapterItem> oneChilds= new ArrayList<>(); List<CityBean.CitysBean> citys = data.getCitys(); if (citys == null) {//如果沒有二級數據就直接返回.  return null; } for (int i = 0; i < citys.size(); i++) {//遍歷二級數據.  TwoItem twoItem = new TwoItem(citys.get(i));//創建二級條目。  oneChilds.add(twoItem); } return oneChilds; } @Override protected int initLayoutId() {//當前級數的布局 return R.layout.itme_one; } @Override public void onExpand() { super.onExpand(); } @Override public void onBindViewHolder(ViewHolder holder) { //設置當前級數的viewhodler. //如果需要某個view展開關閉時的動畫,可以在這里保存view到成員變量。 //然后在onExpand()方法里面操作。 holder.setText(R.id.tv_content, data.getProvinceName()); }}

如果是同一級想要設置不同的布局,接著看

/** * Created by baozi on 2016/12/8. */public class FourItem extends TreeAdapterItem<String> {.... @Override protected List<TreeAdapterItem> initChildsList(String data) { ArrayList<TreeAdapterItem> treeAdapterItems = new ArrayList<>(); for (int i = 0; i < 10; i++) {  FiveItem threeItem = new FiveItem("我是五級");  //在遍歷的時候,通過條件,重設孩子的布局id.和所占比  if (i % 4 == 0) {//偷個懶,不多寫布局了.  threeItem.setLayoutId(R.layout.itme_one);  threeItem.setSpanSize(0);  } else if (i % 3 == 0) {  threeItem.setLayoutId(R.layout.item_two);  threeItem.setSpanSize(2);  }  treeAdapterItems.add(threeItem); } return treeAdapterItems; }....}
/** * Created by baozi on 2016/12/8. */public class FiveItem extends TreeAdapterItem<String> { .......//設置默認的布局 @Override protected int initLayoutId() { return R.layout.item_five; }//設置默認的占比 @Override public int initSpansize() { return 2; } //根據layoutId來判斷viewhodler并設置 @Override public void onBindViewHolder(ViewHolder holder) { if (layoutId == R.layout.itme_one) {  holder.setText(R.id.tv_content, "我是第一種五級"); } else if (layoutId == R.layout.item_five) {  holder.setText(R.id.tv_content, "我是第二種五級"); }else if (layoutId == R.layout.item_two) {  holder.setText(R.id.tv_content, "我是第三種五級"); } }}

 

下面附上Demo下載地址:

github傳送門:TreeRecyclerView

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對VEVB武林網的支持。


注:相關教程知識閱讀請移步到Android開發頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 南京市| 信丰县| 民乐县| 宜宾县| 册亨县| 鄂托克前旗| 苏尼特右旗| 吴忠市| 徐闻县| 浦北县| 建始县| 保定市| 榕江县| 土默特左旗| 英吉沙县| 铁力市| 阿勒泰市| 台东市| 民乐县| 通化市| 黄梅县| 广灵县| 尼玛县| 巧家县| 宜昌市| 焦作市| 晋宁县| 潢川县| 阿拉善盟| 鹤庆县| 沙河市| 东丽区| 炎陵县| 黄大仙区| 泌阳县| 桦南县| 和政县| 邵武市| 勐海县| 旌德县| 榆树市|