公司项目中有一个选择联系人的界面,一看里面关系极其复杂,最多时有5层关系嵌套,层数还不一定,有的是第五级是人员,有的是第四级是人员,崩溃中……原来的实现方式是分了三个Activity去分别加载,个人觉得太过臃肿麻烦,选个人要调四次页面,太繁琐了。就想能不能把它整到一个页面中去,既能全选所有人又能实现单选几个人。
刚开始尝试着用 ExpandableListView 实现,效果是实现了但全选状态传递不好弄,如何点击某一层节点,让它的所有孩子都选中?整了半天没整好。心想这轮子肯定有人造过了,本着不重复造轮子的理念,去网上找找看吧。
看了 n 篇文章后,总结一下就是两种解决方案,一种是用 ExpandableListView 实现,还没有见到有案例实现全选的。另一种是直接用 ListView 实现 n 级嵌套,还能全选全不选!就第二种了。
用 ListView 实现的文章几乎所有案例都参照了 鸿神 的那篇 Android 打造任意层级树形控件 考验你的数据结构和设计, 默默的献上膝盖~
鸿神的这篇文章大概看了下,因为后面有很多人都在这个基础上做的优化,原理也写的很详细,索性直接研究后者吧。几经筛选最终挑出了这篇:更快实现Android多级树形选择列表
借鉴了上面的经验之后,顺利的做了出来。
先上图:
选择联系人.gif分析
实现原理我就不多说啦,上面两篇文章里都讲的很清楚了。简单来讲就是把所有节点都当成一个 Node 对象,Node 对象里有该节点的 id, 它的父节点的 id:pId, 它所有子节点的 list 集合: children, 该节点的层级 level 等等。在设置数据的时候就对数据进行处理,把层级关系排好,按层级依次显示。当选中某个节点时,将它的父节点设置为选中,再将它的所有子节点循环一遍都设置为选中,就解决了全选问题。
用法
本案例中我将选择联系人的操作封装到了一个 Activity 里面,用的时候很简单,只需启动 Activity 的时候传两个参数就可以:
Intent intent = new Intent(this, SelectReceiverActivity.class);
//要请求的数据类型,将项目中用到的类型都封装到枚举类 ReceiverType 里
intent.putExtra("type", ReceiverType.TEACHER);
//本次请求的标记,用于当一个页面要多次调用选人界面时,拿到选择结果的时候做区分
intent.putExtra("flag", "record");
startActivity(intent);
选择的结果通过 EventBus 传递,不了解 EventBus 的请自行补习~
EventBus 的接收事件
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEvent(SelectReceiverEvent event){
String flag = event.getFlag();
/* 如果没传flag可省去判空操作,也可省去判断flag的操作
直接根据需要对数据进行处理 */
if(flag == null){
return;
}
if(TextUtils.equals("flag1", flag)){
//你自己的操作
}else if(TextUtils.equals("flag2", flag)){
//你自己的操作
}
}
实现
温馨提示:下面的代码可直接复制到你的项目中,根据需要进行删改。手把手教你怎么快速集成到项目中。
先偷个懒,为了能直接用 zhangke3016
的四个工具类,先建个跟他项目一样的包:com.multilevel.treelist
,然后将 Node.java
, OnTreeNodeClickListener.java
, TreeHelper.java
, TreeListViewAdapter.java
四个类直接拷到这个包下。
上代码
工具类篇
跟业务关系不大,可直接拷贝
Node.java
这是节点对象,里面封装了能用到的所有信息,是多级列表的核心类
package com.multilevel.treelist;
import java.util.ArrayList;
import java.util.List;
public class Node<T,B> {
/**
* 传入的实体对象
*/
public B bean;
/**
* 设置开启 关闭的图片
*/
public int iconExpand=-1, iconNoExpand = -1;
private T id;
/**
* 根节点pId为0
*/
private T pId ;
private String name;
/**
* 当前的级别
*/
private int level;
/**
* 是否展开
*/
private boolean isExpand = false;
private int icon = -1;
/**
* 下一级的子Node
*/
private List<Node> children = new ArrayList<>();
/**
* 父Node
*/
private Node parent;
/**
* 是否被checked选中
*/
private boolean isChecked;
/**
* 是否为新添加的
*/
public boolean isNewAdd = true;
/**
* 该分组下的人数
*/
private int count;
/**
* 是否是人,1=true, 0=false
*/
private int isPeople;
public boolean isChecked() {
return isChecked;
}
public void setChecked(boolean isChecked) {
this.isChecked = isChecked;
}
public Node() {}
public Node(T id, T pId, String name) {
super();
this.id = id;
this.pId = pId;
this.name = name;
}
public Node(T id, T pId, String name, B bean) {
super();
this.id = id;
this.pId = pId;
this.name = name;
this.bean = bean;
}
public Node(T id, T pId, String name, int count) {
this.id = id;
this.pId = pId;
this.name = name;
this.count = count;
}
public Node(T id, T pId, String name, int count, int isPeople) {
this.id = id;
this.pId = pId;
this.name = name;
this.count = count;
this.isPeople = isPeople;
}
public int getIcon()
{
return icon;
}
public void setIcon(int icon)
{
this.icon = icon;
}
public T getId()
{
return id;
}
public void setId(T id)
{
this.id = id;
}
public T getpId()
{
return pId;
}
public void setpId(T pId)
{
this.pId = pId;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public void setLevel(int level) {
this.level = level;
}
public boolean isExpand() {
return isExpand;
}
public List<Node> getChildren() {
return children;
}
public void setChildren(List<Node> children) {
this.children = children;
}
public Node getParent() {
return parent;
}
public void setParent(Node parent) {
this.parent = parent;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public int getIsPeople() {
return isPeople;
}
public void setIsPeople(int isPeople) {
this.isPeople = isPeople;
}
/**
* 是否为跟节点
*
* @return
*/
public boolean isRoot() {
return parent == null;
}
/**
* 判断父节点是否展开
*
* @return
*/
public boolean isParentExpand() {
if (parent == null)
return false;
return parent.isExpand();
}
/**
* 是否是叶子界点
*
* @return
*/
public boolean isLeaf()
{
return children.size() == 0;
}
/**
* 获取level
*/
public int getLevel() {
return parent == null ? 0 : parent.getLevel() + 1;
}
/**
* 设置展开
*
* @param isExpand
*/
public void setExpand(boolean isExpand) {
this.isExpand = isExpand;
if (!isExpand) {
for (Node node : children) {
node.setExpand(isExpand);
}
}
}
@Override
public String toString() {
return "Node{" +
"id=" + id +
", pId=" + pId +
", name='" + name + '\'' +
", level=" + level +
", isPeople=" + isPeople +
", count=" + count +
'}';
}
}
TreeHelper.java
节点对象 Node 的工具类,对 Node 相关操作的封装
package com.multilevel.treelist;
import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.List;
public class TreeHelper {
/**
* 传入node 返回排序后的Node
*
* @param datas
* @param defaultExpandLevel
* @return
* @throws IllegalArgumentException
* @throws IllegalAccessException
*/
public static List<Node> getSortedNodes(List<Node> datas,
int defaultExpandLevel) {
List<Node> result = new ArrayList<Node>();
// 设置Node间父子关系
List<Node> nodes = convetData2Node(datas);
// 拿到根节点
List<Node> rootNodes = getRootNodes(nodes);
// 排序以及设置Node间关系
for (Node node : rootNodes) {
addNode(result, node, defaultExpandLevel, 1);
}
return result;
}
/**
* 过滤出所有可见的Node
*
* @param nodes
* @return
*/
public static List<Node> filterVisibleNode(List<Node> nodes) {
List<Node> result = new ArrayList<Node>();
for (Node node : nodes) {
// 如果为跟节点,或者上层目录为展开状态
if (node.isRoot() || node.isParentExpand()) {
setNodeIcon(node);
result.add(node);
}
}
return result;
}
/**
* 设置Node间,父子关系;让每两个节点都比较一次,即可设置其中的关系
*/
private static List<Node> convetData2Node(List<Node> nodes) {
for (int i = 0; i < nodes.size(); i++) {
Node n = nodes.get(i);
for (int j = i + 1; j < nodes.size(); j++) {
Node m = nodes.get(j);
if (m.getpId() == n.getId()) {
n.getChildren().add(m);
m.setParent(n);
} else if (m.getId() == n.getpId()) {
m.getChildren().add(n);
n.setParent(m);
}
}
}
return nodes;
}
private static List<Node> getRootNodes(List<Node> nodes) {
List<Node> root = new ArrayList<Node>();
for (Node node : nodes) {
if (node.isRoot())
root.add(node);
}
return root;
}
/**
* 把一个节点上的所有的内容都挂上去
*/
private static <T,B> void addNode(List<Node> nodes, Node<T,B> node,
int defaultExpandLeval, int currentLevel) {
nodes.add(node);
if (node.isNewAdd && defaultExpandLeval >= currentLevel) {
node.setExpand(true);
}
if (node.isLeaf())
return;
for (int i = 0; i < node.getChildren().size(); i++) {
addNode(nodes, node.getChildren().get(i), defaultExpandLeval,
currentLevel + 1);
}
}
/**
* 设置节点的图标
*
* @param node
*/
private static void setNodeIcon(Node node) {
if (node.getChildren().size() > 0 && node.isExpand()) {
node.setIcon(node.iconExpand);
} else if (node.getChildren().size() > 0 && !node.isExpand()) {
node.setIcon(node.iconNoExpand);
} else {
node.setIcon(-1);
}
}
}
TreeListViewAdapter.java
对 ListView 的 Adapter 的封装
package com.multilevel.treelist;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ListView;
import java.util.ArrayList;
import java.util.List;
public abstract class TreeListViewAdapter extends BaseAdapter {
protected Context mContext;
/**
* 存储所有可见的Node
*/
protected List<Node> mNodes = new ArrayList<>();
protected LayoutInflater mInflater;
private List<Node> mDatas = new ArrayList<>();
private ListView mTree;
/**
* 存储所有的Node
*/
protected List<Node> mAllNodes = new ArrayList<>();
/**
* 点击的回调接口
*/
private OnTreeNodeClickListener onTreeNodeClickListener;
/**
* 默认不展开
*/
private int defaultExpandLevel = 0;
/**
* 展开与关闭的图片
*/
private int iconExpand = -1, iconNoExpand = -1;
public void setOnTreeNodeClickListener(
OnTreeNodeClickListener onTreeNodeClickListener) {
this.onTreeNodeClickListener = onTreeNodeClickListener;
}
public TreeListViewAdapter(ListView mTree, Context context, List<Node> datas,
int defaultExpandLevel, int iconExpand, int iconNoExpand) {
this.iconExpand = iconExpand;
this.iconNoExpand = iconNoExpand;
this.mDatas = datas;
this.defaultExpandLevel = defaultExpandLevel;
mContext = context;
this.mTree = mTree;
initData();
}
private void initData() {
for (Node node : mDatas) {
node.getChildren().clear();
node.iconExpand = iconExpand;
node.iconNoExpand = iconNoExpand;
}
/**
* 对所有的Node进行排序
*/
mAllNodes = TreeHelper.getSortedNodes(mDatas, defaultExpandLevel);
/**
* 过滤出可见的Node
*/
mNodes = TreeHelper.filterVisibleNode(mAllNodes);
mInflater = LayoutInflater.from(mContext);
/**
* 设置节点点击时,可以展开以及关闭;并且将ItemClick事件继续往外公布
*/
mTree.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
expandOrCollapse(position);
if (onTreeNodeClickListener != null) {
onTreeNodeClickListener.onClick(mNodes.get(position),
position);
}
}
});
}
/**
* @param mTree
* @param context
* @param datas
* @param defaultExpandLevel 默认展开几级树
*/
public TreeListViewAdapter(ListView mTree, Context context, List<Node> datas,
int defaultExpandLevel) {
this(mTree, context, datas, defaultExpandLevel, -1, -1);
}
/**
* 清除掉之前数据并刷新 重新添加
*
* @param mlists
* @param defaultExpandLevel 默认展开几级列表
*/
public void addDataAll(List<Node> mlists, int defaultExpandLevel) {
mAllNodes.clear();
addData(-1, mlists, defaultExpandLevel);
}
/**
* 在指定位置添加数据并刷新 可指定刷新后显示层级
*
* @param index
* @param mlists
* @param defaultExpandLevel 默认展开几级列表
*/
public void addData(int index, List<Node> mlists, int defaultExpandLevel) {
this.defaultExpandLevel = defaultExpandLevel;
notifyData(index, mlists);
}
/**
* 在指定位置添加数据并刷新
*
* @param index
* @param mlists
*/
public void addData(int index, List<Node> mlists) {
notifyData(index, mlists);
}
/**
* 添加数据并刷新
*
* @param mlists
*/
public void addData(List<Node> mlists) {
addData(mlists, defaultExpandLevel);
}
/**
* 添加数据并刷新 可指定刷新后显示层级
*
* @param mlists
* @param defaultExpandLevel
*/
public void addData(List<Node> mlists, int defaultExpandLevel) {
this.defaultExpandLevel = defaultExpandLevel;
notifyData(-1, mlists);
}
/**
* 添加数据并刷新
*
* @param node
*/
public void addData(Node node) {
addData(node, defaultExpandLevel);
}
/**
* 添加数据并刷新 可指定刷新后显示层级
*
* @param node
* @param defaultExpandLevel
*/
public void addData(Node node, int defaultExpandLevel) {
List<Node> nodes = new ArrayList<>();
nodes.add(node);
this.defaultExpandLevel = defaultExpandLevel;
notifyData(-1, nodes);
}
/**
* 刷新数据
*
* @param index
* @param mListNodes
*/
private void notifyData(int index, List<Node> mListNodes) {
for (int i = 0; i < mListNodes.size(); i++) {
Node node = mListNodes.get(i);
node.getChildren().clear();
node.iconExpand = iconExpand;
node.iconNoExpand = iconNoExpand;
}
for (int i = 0; i < mAllNodes.size(); i++) {
Node node = mAllNodes.get(i);
node.getChildren().clear();
node.isNewAdd = false;
}
if (index != -1) {
mAllNodes.addAll(index, mListNodes);
} else {
mAllNodes.addAll(mListNodes);
}
/**
* 对所有的Node进行排序
*/
mAllNodes = TreeHelper.getSortedNodes(mAllNodes, defaultExpandLevel);
/**
* 过滤出可见的Node
*/
mNodes = TreeHelper.filterVisibleNode(mAllNodes);
//刷新数据
notifyDataSetChanged();
}
/**
* 获取排序后所有节点
*
* @return
*/
public List<Node> getAllNodes() {
if (mAllNodes == null)
mAllNodes = new ArrayList<Node>();
return mAllNodes;
}
/**
* 相应ListView的点击事件 展开或关闭某节点
*
* @param position
*/
public void expandOrCollapse(int position) {
Node n = mNodes.get(position);
if (n != null) {// 排除传入参数错误异常
if (!n.isLeaf()) {
n.setExpand(!n.isExpand());
mNodes = TreeHelper.filterVisibleNode(mAllNodes);
notifyDataSetChanged();// 刷新视图
}
}
}
@Override
public int getCount() {
return mNodes.size();
}
@Override
public Object getItem(int position) {
return mNodes.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
Node node = mNodes.get(position);
convertView = getConvertView(node, position, convertView, parent);
// 设置内边距
convertView.setPadding(node.getLevel() * CommonUtils.dp2px(mContext, 20), 3, 3, 3);
return convertView;
}
/**
* 设置多选
*
* @param node
* @param checked
*/
protected void setChecked(final Node node, boolean checked) {
node.setChecked(checked);
setChildChecked(node, checked);
if (node.getParent() != null)
setNodeParentChecked(node.getParent(), checked);
notifyDataSetChanged();
}
/**
* 设置是否选中
*
* @param node
* @param checked
*/
public <T, B> void setChildChecked(Node<T, B> node, boolean checked) {
if (!node.isLeaf()) {
node.setChecked(checked);
for (Node childrenNode : node.getChildren()) {
setChildChecked(childrenNode, checked);
}
} else {
node.setChecked(checked);
}
}
private void setNodeParentChecked(Node node, boolean checked) {
if (checked) {
node.setChecked(checked);
if (node.getParent() != null)
setNodeParentChecked(node.getParent(), checked);
} else {
List<Node> childrens = node.getChildren();
boolean isChecked = false;
for (Node children : childrens) {
if (children.isChecked()) {
isChecked = true;
}
}
//如果所有自节点都没有被选中 父节点也不选中
if (!isChecked) {
node.setChecked(checked);
}
if (node.getParent() != null)
setNodeParentChecked(node.getParent(), checked);
}
}
public abstract View getConvertView(Node node, int position,
View convertView, ViewGroup parent);
public void setData(List<Node> datas) {
this.mDatas = datas;
initData();
}
}
OnTreeNodeClickListener.java
监听节点点击的监听器
package com.multilevel.treelist;
public interface OnTreeNodeClickListener {
void onClick(Node node, int position);
}
将以上四个类拷贝进项目中去,算是工具类,一般情况下这几个类不用变,Node 的属性可根据需要增删。下面就是项目的具体实现了:
具体业务实现篇
下面跟业务强相关,需要根据自己的项目做相应修改
SelectReceiverActivity.java
实现多级菜单的最终封装体,可直接被调用
/**
* 选择联系人的Activity
* 用法:直接启动该Activity,intent传参数 "type",值为枚举值ReceiverType
* flag 参数可传可不传,是用来标记是谁请求的。主要用于一个页面请求多次来做区分
* 传值用EventBus。在需要接受选人结果的页面注册EventBus,并接收事件SelectReceiverEvent
* SelectReceiverEvent事件封装了 选择的人数count 和 选择的人的id拼成的字符串
*/
public class SelectReceiverActivity extends BaseActivity {
private ListView lv;
private List<Node> mDatas = new ArrayList<>();
private static final String ALL = "all";
private static final String TEACHER = "teacher";
private static final String STUDENT = "student";
private static final String PARENT = "parent";
private ReceiverSelectService service;
private String token;
private CloseableRxServiceExecutor executor;
private Context context;
private SimpleTreeAdapter mAdapter;
private CustomProgressDialog progressDialog;
private CommonTitleView titleView;
private int studentTotal; //学生总人数
private int parentTotal; //家长总人数
private int teacherTotal; //老师总人数
private Intent intent;
private String userTypes = "";
private String flag;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_select_receiver2);
context = MyApplication.getContext();
initUserTypes();
initView();
initData();
}
private void initUserTypes() {
Intent intent = getIntent();
//flag用来标记是谁启动了它,如果flag不为空,Event将flag返回,作为区别的标识
flag = intent.getStringExtra("flag");
ReceiverType type = (ReceiverType) intent.getSerializableExtra("type");
//自己的逻辑。根据传的 type 请求不同的数据
}
private void initView() {
lv = (ListView) findViewById(R.id.lv);
titleView = (CommonTitleView) findViewById(R.id.title_view);
}
private void initData() {
initTitle();
//网络请求的服务类,用的 retrofit 框架
service = ApiManager.getReceiverSelectService();
//RxJava 封装的工具类
executor = new CloseableRxServiceExecutor();
//当前用户的token
token = StringUtils.getToken(this);
//加载中进度条
progressDialog = CustomProgressDialog.create(this, CommonUtils.getResString(R.string.load_data));
progressDialog.show();
//Retrofit + RxJava 网络请求
Single<DataModel> single = service.getAppUser(token, userTypes);
executor.execute(single, new Action1<DataModel>() {
@Override
public void call(DataModel dataModel) {
setListData(dataModel);
}
}, new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
progressDialog.dismiss();
ToastUtils.showToast(CommonUtils.getResString(R.string.request_data_error));
}
});
}
/**
* 解析服务器返回的数据。让服务器把所有的人都包装到json里返回了
* 所以拿到数据后要拆分开
* 这里要替换为你自己的逻辑
*/
private void setListData(DataModel dataModel) {
List<GradeModel> studentData = dataModel.getStudent();
List<GradeModel> parentData = dataModel.getParent();
List<GradeModel> teacherData = dataModel.getTeacher();
if (studentData != null && studentData.size() != 0) {
//遍历学生
for (GradeModel model : studentData) {
studentTotal += model.getCount();
//将年级数据封装进集合,第三级菜单
mDatas.add(new Node(model.getId(), STUDENT, model.getName(), model.getCount(), model.getIsPeople()));
//遍历班级
List<ClassModel> classList = model.getList();
if (classList != null && classList.size() != 0) {
for (ClassModel classModel : classList) {
String classId = classModel.getId();
//将班级数据封装进集合,第四级菜单
mDatas.add(new Node(classId, model.getId(), classModel.getName(), classModel.getCount(), classModel.getIsPeople()));
//遍历人员
List<StudentModel> studentList = classModel.getList();
if (studentList != null && studentList.size() != 0) {
for (StudentModel stuModel : studentList) {
//将人员数据封装进集合,第五级菜单
Node stuNode = new Node(stuModel.getId(), classId, stuModel.getName(), 0, stuModel.getIsPeople());
mDatas.add(stuNode);
}
}
}
}
}
//创建第二级菜单
mDatas.add(new Node(STUDENT, ALL, "学生", studentTotal));
}
if (parentData != null && parentData.size() != 0) {
//遍历家长
for (GradeModel model : parentData) {
parentTotal += model.getCount();
mDatas.add(new Node(model.getId(), PARENT, model.getName(), model.getCount(), model.getIsPeople()));
//遍历班级
List<ClassModel> classList = model.getList();
if (classList != null && classList.size() != 0) {
for (ClassModel classModel : classList) {
String classId = classModel.getId();
mDatas.add(new Node(classId, model.getId(), classModel.getName(), classModel.getCount(), classModel.getIsPeople()));
//遍历人员
List<StudentModel> studentList = classModel.getList();
if (studentList != null && studentList.size() != 0) {
for (StudentModel stuModel : studentList) {
Node stuNode = new Node(stuModel.getId(), classId, stuModel.getName(), 0, stuModel.getIsPeople());
mDatas.add(stuNode);
}
}
}
}
}
mDatas.add(new Node(PARENT, ALL, "家长", parentTotal));
}
if (teacherData != null && teacherData.size() != 0) {
//遍历老师
for (GradeModel model : teacherData) {
teacherTotal += model.getCount();
mDatas.add(new Node(model.getId(), TEACHER, model.getName(), model.getCount(), model.getIsPeople()));
//遍历班级
List<ClassModel> classList = model.getList();
if (classList != null && classList.size() != 0) {
for (ClassModel classModel : classList) {
String classId = classModel.getId();
mDatas.add(new Node(classId, model.getId(), classModel.getName(), classModel.getCount(), classModel.getIsPeople()));
//遍历人员
List<StudentModel> studentList = classModel.getList();
if (studentList != null && studentList.size() != 0) {
for (StudentModel stuModel : studentList) {
Node stuNode = new Node(stuModel.getId(), classId, stuModel.getName(), 0, stuModel.getIsPeople());
mDatas.add(stuNode);
}
}
}
}
}
mDatas.add(new Node(TEACHER, ALL, "教师", teacherTotal));
}
progressDialog.dismiss();
//所有人数
int allTotal = parentTotal + studentTotal + teacherTotal;
//创建第一级菜单
mDatas.add(new Node(ALL, "-1", "全体人员", allTotal));
//给 ListView 设置 Adapter
mAdapter = new SimpleTreeAdapter(lv, context, mDatas, 1, R.drawable.icon_sub, R.drawable.icon_add);
lv.setAdapter(mAdapter);
}
private void initTitle() {
titleView.setTitleShowType(CommonTitleView.ShowType.MIDDLE_TEXT_AND_RIGHT_TEXT);
titleView.setMiddleText("选择接收人");
titleView.setRightText("确定");
titleView.setOnBackButtonClick(new CommonTitleView.OnBackButtonClick() {
@Override
public void onBackClick() {
finish();
}
});
//点击确定按钮
titleView.setOnRightTextClick(new CommonTitleView.OnRightTextClick() {
@Override
public void onTextClick() {
if (mAdapter == null) {
return;
}
List<Node> allNodes = mAdapter.getAllNodes();
List<String> selectNodesId = new ArrayList<String>();
for (Node node : allNodes) {
if (node.isChecked() && (node.getIsPeople() == 1)) {
selectNodesId.add(node.getId().toString());
}
}
//去重操作
List list = CommonUtils.deleteRepeat(selectNodesId);
//格式化
String ids = list.toString();
String substring = ids.substring(1, ids.length() - 1);
String result = substring.replace(", ", ",");
//用EventBus发送选中的ids 和 一共选了多少人
if (flag == null) {
EventBus.getDefault().post(new SelectReceiverEvent(list.size(), result));
} else {
//flag不为空,返回
EventBus.getDefault().post(new SelectReceiverEvent(list.size(), result, flag));
}
finish();
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
//取消请求
try {
executor.close();
} catch (IOException e) {
e.printStackTrace();
}
//关闭加载中进度条
if (progressDialog != null && progressDialog.isShowing()) {
progressDialog.dismiss();
}
}
}
SimpleTreeAdapter
自定义的Adapter,继承了 TreeListViewAdapter
public class SimpleTreeAdapter extends TreeListViewAdapter {
private Context context;
public SimpleTreeAdapter(ListView mTree, Context context, List<Node> datas, int defaultExpandLevel, int iconExpand, int iconNoExpand) {
super(mTree, context, datas, defaultExpandLevel, iconExpand, iconNoExpand);
this.context = context;
}
@Override
public View getConvertView(final Node node, int position, View convertView, ViewGroup parent) {
View view;
final ViewHolder holder;
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.item_receiver_select_title, null);
holder = new ViewHolder();
holder.tvName = (TextView) view.findViewById(R.id.tv_name);
holder.tvCount = (TextView) view.findViewById(R.id.tv_count);
holder.cb = (CheckBox) view.findViewById(R.id.check_box);
holder.iv = (ImageView) view.findViewById(R.id.iv_right);
view.setTag(holder);
} else {
view = convertView;
holder = (ViewHolder) view.getTag();
}
holder.cb.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
setChecked(node, holder.cb.isChecked());
}
});
if (node.isChecked()){
holder.cb.setChecked(true);
}else {
holder.cb.setChecked(false);
}
if (node.getIcon() == -1) {
holder.iv.setVisibility(View.INVISIBLE);
} else {
holder.iv.setVisibility(View.VISIBLE);
holder.iv.setImageResource(node.getIcon());
}
holder.tvName.setText(node.getName());
//不是学生,都显示当前分类下有多少人
if (node.getIsPeople() != 1) {
holder.tvCount.setVisibility(View.VISIBLE);
holder.tvCount.setText("(" + node.getCount() + ")");
} else {
holder.tvCount.setVisibility(View.GONE);
}
return view;
}
class ViewHolder {
TextView tvName, tvCount;
CheckBox cb;
ImageView iv;
}
}
资源文件 item_receiver_select_title.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/selector_list_item_bg_gray2gray"
android:descendantFocusability="blocksDescendants"
android:orientation="horizontal">
<CheckBox
android:id="@+id/check_box"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="5dp"
android:button="@drawable/selector_checkbox" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:paddingBottom="10dp"
android:paddingTop="10dp">
<TextView
android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:gravity="center_vertical"
android:text="项目"
android:textColor="@color/black"
android:textSize="15sp" />
<TextView
android:id="@+id/tv_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:gravity="center_vertical"
android:text="(20)"
android:textColor="@color/elec_file_gray_bg"
android:textSize="12sp"
android:visibility="gone" />
</LinearLayout>
<ImageView
android:id="@+id/iv_right"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_gravity="center"
android:layout_marginRight="5dp"
android:src="@drawable/icon_add" />
</LinearLayout>
附上 list 去重方法
/**
* 去除list集合中的重复元素
* @param list 要去重的 list
* @return 返回去重后的 list
*/
public static List deleteRepeat(List list){
List newList = new ArrayList<>();
Set set = new HashSet();
for (Object obj : list) {
if(set.add(obj)){
newList.add(obj);
}
}
return newList;
}
好啦,以上就是实现多级树形选择列表的方法,直接拷到项目中稍加修改就能用。
如有疑问可以在评论区进行交流。
网友评论