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

首頁 > 系統(tǒng) > Android > 正文

Android 繪制多級樹形選擇列表實例代碼

2019-10-22 18:15:38
字體:
供稿:網(wǎng)友

一、概述

前段時間有個項目的需要在Android端顯示一個復(fù)選的多層樹形控件,主要展示一個公司的組織架構(gòu),類似總部下面有各個部門,部門之下是組和員工等。另外需要加上展開與回收部門詳情、關(guān)閉部分已開展的布局、勾選等功能。

效果圖如下:

android,繪制樹形列表,多級樹形選擇列表

二、思路分析

毫無疑問,對于這種數(shù)據(jù)可能達(dá)到幾千幾萬行的列表視圖,我們需要選擇recyclerview等具有回收item功能的控件,因此Item的狀態(tài)保持放在Model中而不是View中。

由于原始數(shù)據(jù)是樹形結(jié)構(gòu)的,我們需要先將樹形結(jié)構(gòu)轉(zhuǎn)換為列表數(shù)據(jù),類似根結(jié)點 - 父節(jié)點1 - 子結(jié)點1 - 子節(jié)點2 - 父節(jié)點2......這種形式 - 這恰恰是樹的前序遍歷

android,繪制樹形列表,多級樹形選擇列表

實現(xiàn)思路 - 為了更簡潔明白,左右顛倒處理

三、具體實現(xiàn)

簡單的節(jié)點實現(xiàn)

public abstract class SimpleTreeNode {//層級protected int hierarchy;//父節(jié)點protected K parent = null;//子節(jié)點protected final List<K> children = new ArrayList<>();protected boolean isSelected;  // 是否被選中protected boolean isExpand;   // 是否展開}前序遍歷則發(fā)生在adapter的getItem和getItemCount的時候public T getItem(int position) {  int[] cur = {position};  return getNode(topGroups, cur);}/** * 先序遍歷 - 獲取指定位置的節(jié)點 * * @param nodes  nodes * @param position itemPosition 數(shù)組只是為了實現(xiàn)手動box實現(xiàn)共享position * @return MultiSelectNode or null */ protected T getNode(List<T> nodes, final int[] position) {  for (T node : nodes) {    if (position[0] == 0) {      return node;    }    position[0]--;    if (node.getChildren().size() > 0) {      T finalNode = getNode(node.getChildren(), position);      if (finalNode != null) {        return finalNode;      }    }  }  return null;} /** * 先序遍歷 - 獲取展示的總長度 (isExpand = true) * * @param nodes nodes * @return int */protected int getTreeSize(List<T> nodes) {  int size = 0;  for (T node : nodes) {    size++;    size += getTreeSize(node.getChildren());    }  return size;}

對于如何實現(xiàn)展開和收縮的功能,我嘗試了兩種方式:

在渲染item的時候判斷node.isExpand = false時,對item進行Gone處理,實際處理發(fā)現(xiàn)列表卡頓非常嚴(yán)重:假設(shè)所有的item都是隱藏的,那么因為列表沒有顯示全,所有的item都會進行渲染一遍....

數(shù)據(jù)遍歷的時候?qū)⒎钦归_的數(shù)據(jù)過濾掉:這種方式完美可行,只需要修改下遍歷方法即可

protected int getTreeSize(List<T> nodes) { int size = 0; for (T node : nodes) {   size++;   // 展開過濾   if (node.isExpand()) {     size += getTreeSize(node.getChildren());   } } return size; } protected T getNode(List<T> nodes, final int[] position) { for (T node : nodes) {   if (position[0] == 0) {     return node;   }   position[0]--;   // 展開過濾   if (node.isExpand() && node.getChildren().size() > 0) {     T finalNode = getNode(node.getChildren(), position);     if (finalNode != null) {       return finalNode;     }   } } return null; }

以上多級樹形列表的展開與隱藏便完成了,剩下的便是對樹節(jié)點的一些操作:例如一個item展開的時候?qū)ζ渌塱tem隱藏;一個item被勾選或取消勾選的時候改變其父節(jié)點和子節(jié)點的狀態(tài)等。對于這些操作,我采用了類似Motion Event的方式 - 用事件傳遞與分發(fā)來處理。

比如展開的時候同級的item隱藏,其實便是通知兄弟節(jié)點設(shè)置expand為false。

android,繪制樹形列表,多級樹形選擇列表

通知兄弟節(jié)點

勾選的操作稍麻煩,可能需要遞歸通知父節(jié)點檢查更新,以及遞歸通知子節(jié)點勾選操作,取消勾選亦如此。

關(guān)鍵代碼如下

/** * Class: SimpleTreeNode * Author: zwgg * Date: 2017/10/16 * Time: 10:35 * 簡單的樹節(jié)點模板類 * 這個自限定泛型可能有點費解:用于以基類導(dǎo)出類作為自身的泛型,以實現(xiàn)模板功能 * 例如:ClassNameA extend SimpleTreeNode< ClassNameA , T > * @see Enum */ public abstract class SimpleTreeNode<K extends SimpleTreeNode<K, T>, T extends TreeNodeEvent> {  //層級  protected int hierarchy;  //父節(jié)點  protected K parent = null;  //子節(jié)點  protected final List<K> children = new ArrayList<>();  public SimpleTreeNode() {  }  public SimpleTreeNode(int hierarchy) {    this.hierarchy = hierarchy;  }  public void bindingParent(K parent) {    this.parent = parent;  }  public void bindingChild(K child) {    this.children.add(child);  }  public void bindingChildren(List<K> children) {    this.children.clear();    this.children.addAll(children);  }  public void dataBinding(K parent, K child) {    parent.bindingChild(child);    child.bindingParent(parent);  }  public int getHierarchy() {    return hierarchy;  }  public void setHierarchy(int hierarchy) {    this.hierarchy = hierarchy;  }  /**   * 通知父節(jié)點   * @param event event   */  public void notifyParent(T event) {    if (parent != null) {      event.setNotifyType(TreeNodeEvent.NOTIFY_PARENT);      parent.onEvent(event);    }  }  /**   * 通知子節(jié)點   * @param event event   */  public void notifyChildren(T event) {    event.setNotifyType(TreeNodeEvent.NOTIFY_CHILDREN);    for (K child : children) {      child.onEvent(event);    }  }  /**   * 通知兄弟節(jié)點 - 需要具有相同的Parent   * @param event event   */  public void notifyBrother(T event) {    if (parent != null) {      event.setNotifyType(TreeNodeEvent.NOTIFY_BROTHER);      for (K child : parent.children) {        if (child != this) {          child.onEvent(event);        }      }    }  }  public abstract void onEvent(T event);  public List<K> getChildren() {    return children;  }  }

業(yè)務(wù)節(jié)點

public class MultiSelectNode<T extends MultiSelectNode<T>> extends SimpleTreeNode<T, MultiSelectEvent> {  private boolean isSelected;  // 是否被選中  private boolean isExpand;   // 是否展開  /**   * @param hierarchy view層級 - 用于產(chǎn)生viewType   */  public MultiSelectNode(int hierarchy) {    super(hierarchy);  }  /**   * 事件處理方法   *   * @param event 傳遞得到的事件   */  @Override  public void onEvent(MultiSelectEvent event) {    switch (event.getNotifyType()) {      case TreeNodeEvent.NOTIFY_CHILDREN:        // 父節(jié)點通知子節(jié)點改變選擇狀態(tài)        if (event.getEventType() == MultiSelectEvent.EVENT_SET_SELECTED) {          // 如果子節(jié)點選擇狀態(tài)有變,則繼續(xù)通知下層節(jié)點改變狀態(tài)          if (event.isSelected() != isSelected()) {            setSelected(event.isSelected());            notifyChildren(event);          }        }        break;      case TreeNodeEvent.NOTIFY_PARENT:        // 子節(jié)點選擇狀態(tài)更改,則通知父節(jié)點重新根據(jù)所有子節(jié)點設(shè)置自身狀態(tài)        if (event.getEventType() == MultiSelectEvent.EVENT_SET_SELECTED) {          if (recheckSelected() != isSelected()) {            setSelected(!isSelected());            // 如果父節(jié)點有變,則繼續(xù)遞歸通知            notifyParent(event);          }        }        break;      case TreeNodeEvent.NOTIFY_BROTHER:        // 通知兄弟節(jié)點改變擴展?fàn)顟B(tài)        if (event.getEventType() == MultiSelectEvent.EVENT_SET_EXPAND) {          if (event.isExpand() != isExpand()) {            setExpand(event.isExpand());          }        }        break;      default:        break;    }  }  /**   * 關(guān)閉兄弟節(jié)點擴展   *   * @param isExpand 是否擴展   */  public void setOtherGroupsExpand(boolean isExpand) {    MultiSelectEvent event = new MultiSelectEvent(MultiSelectEvent.EVENT_SET_EXPAND);    event.setExpand(isExpand);    notifyBrother(event);  }  /**   * 通知父節(jié)點根據(jù)子節(jié)點設(shè)置狀態(tài)   * 注:選擇具有遞歸性,如果父類狀態(tài)有變會繼續(xù)通知父類   */  public void setParentRecheckSelected() {    MultiSelectEvent event = new MultiSelectEvent(MultiSelectEvent.EVENT_SET_SELECTED);    notifyParent(event);  }  /**   * 通知子節(jié)點設(shè)置選擇狀態(tài)   * 注:選擇具有遞歸性,會設(shè)置所有孩子以及孩子的孩子狀態(tài)   *   * @param isSelected 是否選擇   */  public void setChildrenSelected(boolean isSelected) {    MultiSelectEvent event = new MultiSelectEvent(MultiSelectEvent.EVENT_SET_SELECTED);    event.setSelected(isSelected);    notifyChildren(event);  }  /**   * 根據(jù)子節(jié)點設(shè)置自身狀態(tài)   *   * @return isSelected boolean   */  public boolean recheckSelected() {    for (MultiSelectNode child : children) {      if (!child.isSelected()) {        return false;      }    }    return true;  }  public boolean isExpand() {    return isExpand;  }  public void setExpand(boolean expand) {    isExpand = expand;  }  public boolean isSelected() {    return isSelected;  }  public void setSelected(boolean selected) {    isSelected = selected;  }  }

Event事件

public class TreeNodeEvent {  public static final int NOTIFY_PARENT = 1;  public static final int NOTIFY_CHILDREN = 2;  public static final int NOTIFY_BROTHER = 3;  private int notifyType;  public TreeNodeEvent(){  }  public TreeNodeEvent(int notifyType) {    this.notifyType = notifyType;  }  public int getNotifyType() {    return notifyType;  }  public void setNotifyType(int notifyType) {    this.notifyType = notifyType;  }}public class MultiSelectEvent extends TreeNodeEvent {  public static final int EVENT_SET_SELECTED = 1;  public static final int EVENT_SET_EXPAND = 2;  //事件類型  private int eventType;  private boolean isSelected;  private boolean isExpand;}

詳細(xì)可見Github: https://github.com/zwgg/MultiSelectList

總結(jié)

以上所述是小編給大家介紹的Android 繪制多級樹形選擇列表實例代碼,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對VEVB武林網(wǎng)網(wǎng)站的支持!


注:相關(guān)教程知識閱讀請移步到Android開發(fā)頻道。
發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 伊川县| 通河县| 永胜县| 揭东县| 绥滨县| 平遥县| 定远县| 东阿县| 托克托县| 苏尼特右旗| 绥芬河市| 永安市| 鹤庆县| 屏东县| 麻栗坡县| 读书| 苍溪县| 永川市| 孟村| 巴林右旗| 广河县| 泽州县| 沁阳市| 九江县| 吴桥县| 德令哈市| 宜州市| 高密市| 尉氏县| 东宁县| 图木舒克市| 渝中区| 蓝田县| 罗田县| 西藏| 惠水县| 普陀区| 永济市| 大悟县| 礼泉县| 竹山县|