溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

如何在Android中繪制一個多級樹形選擇列表

發(fā)布時間:2021-03-10 16:42:46 來源:億速云 閱讀:451 作者:Leah 欄目:移動開發(fā)

今天就跟大家聊聊有關(guān)如何在Android中繪制一個多級樹形選擇列表,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結(jié)了以下內(nèi)容,希望大家根據(jù)這篇文章可以有所收獲。

具體實現(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進(jìn)行Gone處理,實際處理發(fā)現(xiàn)列表卡頓非常嚴(yán)重:假設(shè)所有的item都是隱藏的,那么因為列表沒有顯示全,所有的item都會進(jìn)行渲染一遍....

數(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;
}

看完上述內(nèi)容,你們對如何在Android中繪制一個多級樹形選擇列表有進(jìn)一步的了解嗎?如果還想了解更多知識或者相關(guān)內(nèi)容,請關(guān)注億速云行業(yè)資訊頻道,感謝大家的支持。

向AI問一下細(xì)節(jié)

免責(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)容。

AI