栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 移动开发 > Android

Android 绘制多级树形选择列表实例代码

Android 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Android 绘制多级树形选择列表实例代码

一、概述

前段时间有个项目的需要在Android端显示一个复选的多层树形控件,主要展示一个公司的组织架构,类似总部下面有各个部门,部门之下是组和员工等。另外需要加上展开与回收部门详情、关闭部分已开展的布局、勾选等功能。

效果图如下:

 

二、思路分析

毫无疑问,对于这种数据可能达到几千几万行的列表视图,我们需要选择recyclerview等具有回收item功能的控件,因此Item的状态保持放在Model中而不是View中。

由于原始数据是树形结构的,我们需要先将树形结构转换为列表数据,类似根结点 - 父节点1 - 子结点1 - 子节点2 - 父节点2......这种形式 - 这恰恰是树的前序遍历

 

实现思路 - 为了更简洁明白,左右颠倒处理

三、具体实现

简单的节点实现

public abstract class SimpleTreeNode {
//层级
protected int hierarchy;
//父节点
protected K parent = null;
//子节点
protected final List children = new ArrayList<>();
protected boolean isSelected;  // 是否被选中
protected boolean isExpand;   // 是否展开
}
前序遍历则发生在adapter的getItem和getItemCount的时候
public T getItem(int position) {
  int[] cur = {position};
  return getNode(topGroups, cur);
}

 protected T getNode(List 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;
}
 
protected int getTreeSize(List nodes) {
  int size = 0;
  for (T node : nodes) {
    size++;
    size += getTreeSize(node.getChildren());
    }
  return size;
}

对于如何实现展开和收缩的功能,我尝试了两种方式:

在渲染item的时候判断node.isExpand = false时,对item进行Gone处理,实际处理发现列表卡顿非常严重:假设所有的item都是隐藏的,那么因为列表没有显示全,所有的item都会进行渲染一遍....

数据遍历的时候将非展开的数据过滤掉:这种方式完美可行,只需要修改下遍历方法即可

protected int getTreeSize(List nodes) {
 int size = 0;
 for (T node : nodes) {
   size++;
   // 展开过滤
   if (node.isExpand()) {
     size += getTreeSize(node.getChildren());
   }
 }
 return size;
 }
 protected T getNode(List 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;
 }

以上多级树形列表的展开与隐藏便完成了,剩下的便是对树节点的一些操作:例如一个item展开的时候对其他同级item隐藏;一个item被勾选或取消勾选的时候改变其父节点和子节点的状态等。对于这些操作,我采用了类似Motion Event的方式 - 用事件传递与分发来处理。

比如展开的时候同级的item隐藏,其实便是通知兄弟节点设置expand为false。

 

通知兄弟节点

勾选的操作稍麻烦,可能需要递归通知父节点检查更新,以及递归通知子节点勾选操作,取消勾选亦如此。

关键代码如下


 public abstract class SimpleTreeNode, T extends TreeNodeEvent> {
  //层级
  protected int hierarchy;
  //父节点
  protected K parent = null;
  //子节点
  protected final List 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 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;
  }
  
  public void notifyParent(T event) {
    if (parent != null) {
      event.setNotifyType(TreeNodeEvent.NOTIFY_PARENT);
      parent.onEvent(event);
    }
  }
  
  public void notifyChildren(T event) {
    event.setNotifyType(TreeNodeEvent.NOTIFY_CHILDREN);
    for (K child : children) {
      child.onEvent(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 getChildren() {
    return children;
  }
  }

业务节点

public class MultiSelectNode> extends SimpleTreeNode {
  private boolean isSelected;  // 是否被选中
  private boolean isExpand;   // 是否展开
  
  public MultiSelectNode(int hierarchy) {
    super(hierarchy);
  }
  
  @Override
  public void onEvent(MultiSelectEvent event) {
    switch (event.getNotifyType()) {
      case TreeNodeEvent.NOTIFY_CHILDREN:
 // 父节点通知子节点改变选择状态
 if (event.getEventType() == MultiSelectEvent.EVENT_SET_SELECTED) {
   // 如果子节点选择状态有变,则继续通知下层节点改变状态
   if (event.isSelected() != isSelected()) {
     setSelected(event.isSelected());
     notifyChildren(event);
   }
 }
 break;
      case TreeNodeEvent.NOTIFY_PARENT:
 // 子节点选择状态更改,则通知父节点重新根据所有子节点设置自身状态
 if (event.getEventType() == MultiSelectEvent.EVENT_SET_SELECTED) {
   if (recheckSelected() != isSelected()) {
     setSelected(!isSelected());
     // 如果父节点有变,则继续递归通知
     notifyParent(event);
   }
 }
 break;
      case TreeNodeEvent.NOTIFY_BROTHER:
 // 通知兄弟节点改变扩展状态
 if (event.getEventType() == MultiSelectEvent.EVENT_SET_EXPAND) {
   if (event.isExpand() != isExpand()) {
     setExpand(event.isExpand());
   }
 }
 break;
      default:
 break;
    }
  }
  
  public void setOtherGroupsExpand(boolean isExpand) {
    MultiSelectEvent event = new MultiSelectEvent(MultiSelectEvent.EVENT_SET_EXPAND);
    event.setExpand(isExpand);
    notifyBrother(event);
  }
  
  public void setParentRecheckSelected() {
    MultiSelectEvent event = new MultiSelectEvent(MultiSelectEvent.EVENT_SET_SELECTED);
    notifyParent(event);
  }
  
  public void setChildrenSelected(boolean isSelected) {
    MultiSelectEvent event = new MultiSelectEvent(MultiSelectEvent.EVENT_SET_SELECTED);
    event.setSelected(isSelected);
    notifyChildren(event);
  }
  
  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;
}

详细可见Github: https://github.com/zwgg/MultiSelectList

总结

以上所述是小编给大家介绍的Android 绘制多级树形选择列表实例代码,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对考高分网网站的支持!

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/156453.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号