我是靠谱客的博主 仁爱咖啡豆,这篇文章主要介绍Android TreeView实现带复选框树形组织结构,现在分享给大家,希望可以做个参考。

之前做项目的时候做人员组织架构时候需要用到,同样可以用于目录视图。简单搜了一下没有合适的,只找到一个基础的有瑕疵的树形结构,就在基础上改了增加了复选框以及简化了部分代码。下面上演示效果图,时长25秒,手机卡见谅。

复选框有两种设计模式:

1、子节点选中则父节点选中,适合多级多item下方便了解哪些被选中;

2、子节点全部选中父节点才选中,更符合日常逻辑,适合少数量以及少层级。

下面上主要代码:

首先上MainActivity,主要作用上加载layout以及读取数据。实际中一般从数据库获取。命名较为随意请见谅。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class MainActivity extends AppCompatActivity { List<Node> list = new ArrayList<Node>(); private TreeListView listView; private RelativeLayout relativeLayout, rl; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); relativeLayout = (RelativeLayout) findViewById(R.id.main_relative_layout); Context context=MainActivity.this; rl = new RelativeLayout(context); rl.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT)); listView = new TreeListView(context, initNodeTree()); listView.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT)); relativeLayout.addView(listView); } public List<Node> initNodeTree() { List<Node> member_list =new ArrayList<Node>(); // -1表示为根节点,id的作用为标识对象身份,第三个参数此例子中是text文本 member_list.add(new Node("" + -1, "1" , "111")); member_list.add(new Node(""+1 , "2" , "222")); member_list.add(new Node("" + -1, "3" , "333")); member_list.add(new Node("" + 1, "4" , "444")); member_list.add(new Node("" + 4, "5" , "555")); member_list.add(new Node("" + 4, "6" , "666")); member_list.add(new Node("" + 4, "7" , "777")); member_list.add(new Node("" + 7, "8" , "888")); member_list.add(new Node("" + 8, "9" , "999")); member_list.add(new Node("" + 8, "10" , "101010")); list.addAll(member_list); return list; } }

接下来是Node类:

Node对象当前主要有父节点Id,自身id以及值组成,自身id自加,父节点id,使用过程中根据实际使用增加成员属性。比如作为组织架构,标识为人名还是一个空的部门,当前对象为第几层级等等,以及从数据库中获取时候直接设置默认选中。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
public class Node implements Serializable { private Node parent = null; // 父节点 private List<Node> childrens = new ArrayList<Node>();//子节点 private String value;//节点显示值 private boolean isChecked = false; //是否被选中 private boolean isExpand = true;//是否处于扩展状态 private boolean hasCheckBox = true;//是否有复选框 private String parentId = null; private String curId = null; //父节点集合 private List<Node> parents = new ArrayList<>(); /** * 设置节点值 * * @param parentId * TODO * @param curId * TODO */ public Node( String parentId, String curId, String value) { // TODO Auto-generated constructor stub this.value = value; this.parentId = parentId; this.curId = curId; } public List<Node> getParents() { return parents; } public void setParents(Node node) { if(node != null) { if (!parents.contains(node)) { parents.add(node); } } } /** * 得到父节点 */ public Node getParent() { return parent; } /** * 设置父节点 * @param parent */ public void setParent(Node parent) { this.parent = parent; } /** * 得到子节点 * @return */ public List<Node> getChildrens() { return childrens; } /** * pandu是否根节点 * @return * */ public boolean isRoot(){ return parent ==null?true:false; } /** * 是否被选中 * @return * */ public boolean isChecked() { return isChecked; } public void setChecked(boolean isChecked) { this.isChecked = isChecked; } /** * 是否是展开状态 * @return * */ public boolean isExplaned() { return isExpand; } /** * 设置展开状态 * @param isExplaned * */ public void setExplaned(boolean isExplaned) { this.isExpand = isExplaned; } /** * 是否有复选框 * @return * */ public boolean hasCheckBox() { return hasCheckBox; } /** * 设置是否有复选框 * @param hasCheckBox * */ public void setHasCheckBox(boolean hasCheckBox) { this.hasCheckBox = hasCheckBox; } /** * 得到节点值 * @return * */ public String getValue() { return value; } /** * 设置节点值 * @param value * */ public void setValue(String value) { this.value = value; } /** * 增加一个子节点 * @param node * */ public void addNode(Node node){ if(!childrens.contains(node)){ childrens.add(node); } } /** * 移除一个子节点 * @param node * */ public void removeNode(Node node){ if(childrens.contains(node)) childrens.remove(node); } /** * 移除指定位置的子节点 * @param location * */ public void removeNode(int location){ childrens.remove(location); } /** * 清除所有子节点 * */ public void clears(){ childrens.clear(); } /** * 判断给出的节点是否当前节点的父节点 * @param node * @return * */ public boolean isParent(Node node){ if(parent == null)return false; if(parent.equals(node))return true; return parent.isParent(node); } /** * 递归获取当前节点级别 * @return * */ public int getLevel(){ return parent ==null?0:parent.getLevel()+1; } /** * 父节点是否处于折叠的状态 * @return * */ public boolean isParentCollapsed(){ if(parent ==null)return false; if(!parent.isExplaned())return true; return parent.isParentCollapsed(); } /** * 是否叶节点(没有展开下级的几点) * @return * */ public boolean isLeaf(){ return childrens.size()<1?true:false; } /** * 返回自己的id * @return **/ public String getCurId() { // TODO Auto-generated method stub return curId; } /** * 返回的父id * @return **/ public String getParentId() { // TODO Auto-generated method stub return parentId; } }

下面是核心代码:

两种选择模式在treeAdapter中进行修改。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
package com.example.administrator.treeview.treeView; import android.content.Context; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.CheckBox; import android.widget.ImageView; import android.widget.TextView; import com.example.administrator.treeview.R; import java.util.ArrayList; import java.util.List; public class TreeAdapter extends BaseAdapter { private Context con; private LayoutInflater lif; public List<Node> all = new ArrayList<Node>();//展示 private List<Node> cache = new ArrayList<Node>();//缓存,记录点状态 private TreeAdapter tree = this; boolean hasCheckBox; private int expandIcon = -1;//展开图标 private int collapseIcon = -1;//收缩图标 ViewItem vi = null; // //存储checkbox选中的集合 // private List<> /** * 构造方法 */ public TreeAdapter(Context context, List<Node> rootNodes){ this.con = context; this.lif = (LayoutInflater)con.getSystemService(Context.LAYOUT_INFLATER_SERVICE); for(int i=0;i<rootNodes.size();i++){ addNode(rootNodes.get(i)); } } /** * 把一个节点上的所有的内容都挂上去 * @param node */ public void addNode(Node node){ all.add(node); cache.add(node); if(node.isLeaf())return; for(int i = 0;i<node.getChildrens().size();i++){ addNode(node.getChildrens().get(i)); } } /** * 设置展开收缩图标 * @param expandIcon * @param collapseIcon */ public void setCollapseAndExpandIcon(int expandIcon,int collapseIcon){ this.collapseIcon = collapseIcon; this.expandIcon = expandIcon; } /** * 一次性对某节点的所有节点进行选中or取消操作 */ public void checkNode(Node n,boolean isChecked){ n.setChecked(isChecked); checkChildren(n,isChecked); // 有一个子节点选中,则父节点选中 if (n.getParent()!=null) checkParent(n,isChecked); // 有一个子节点未选中,则父节点未选中 // unCheckNode(n, isChecked); } /** * 对父节点操作时,同步操作子节点 */ public void checkChildren(Node n,boolean isChecked){ for(int i =0 ;i<n.getChildrens().size();i++){ n.getChildrens().get(i).setChecked(isChecked); checkChildren(n.getChildrens().get(i),isChecked); } } /** * 有一个子节点选中,则父节点选中 */ public void checkParent(Node n,boolean isChecked){ // 有一个子节点选中,则父节点选中 if (n.getParent()!=null&&isChecked){ n.getParent().setChecked(isChecked); checkParent(n.getParent(),isChecked); } // 全部子节点取消选中,则父节点取消选中 if (n.getParent()!=null &&!isChecked){ for (int i = 0; i < n.getParent().getChildrens().size(); i++) { if (n.getParent().getChildrens().get(i).isChecked()) { checkParent(n.getParent(),!isChecked); return ; } } n.getParent().setChecked(isChecked); checkParent(n.getParent(),isChecked); } } /** * 有一个子节点未选中,则父节点未选中 */ public void unCheckNode(Node n, boolean isChecked){ boolean flag = false; n.setChecked(isChecked); if(n.getParent() != null ){ Log.d("parentSize", n.getParent().getChildrens().get(0).isChecked() + ""); for (int i = 0; i < n.getParent().getChildrens().size(); i++) { if((n.getParent().getChildrens().get(i)) != n && (n.getParent().getChildrens().get(i).isChecked() != true)){ flag = true; break; } } if(!flag) { unCheckNode(n.getParent(), isChecked); } } } /** * 获取所有选中节点 * @return * */ public List<Node> getSelectedNode(){ Log.d("getSelectedNode", "我被执行了!"); List<Node> checks =new ArrayList<Node>() ; for(int i = 0;i<cache.size();i++){ Node n =(Node)cache.get(i); if(n.isChecked()) checks.add(n); } return checks; } public void setSelectedNode(List<String> selectedNode){ for (int i=0;i<cache.size();i++) { if(selectedNode.contains(cache.get(i).getCurId())) { cache.get(i).setChecked(true); cache.get(i).getParent().setChecked(true); } } } /** * 设置是否有复选框 * @param hasCheckBox * */ public void setCheckBox(boolean hasCheckBox){ this.hasCheckBox = hasCheckBox; } /** * 控制展开缩放某节点 * @param location * */ public void ExpandOrCollapse(int location){ Node n = all.get(location);//获得当前视图需要处理的节点 if(n!=null)//排除传入参数错误异常 { if(!n.isLeaf()){ n.setExplaned(!n.isExplaned());// 由于该方法是用来控制展开和收缩的,所以取反即可 filterNode();//遍历一下,将所有上级节点展开的节点重新挂上去 this.notifyDataSetChanged();//刷新视图 } } } /** * 设置展开等级 * @param level * */ public void setExpandLevel(int level){ all.clear(); for(int i = 0;i<cache.size();i++){ Node n = cache.get(i); if(n.getLevel()<=level){ if(n.getLevel()<level) n.setExplaned(true); else n.setExplaned(false); all.add(n); } } } /* 清理all,从缓存中将所有父节点不为收缩状态的都挂上去*/ public void filterNode(){ all.clear(); for(int i = 0;i<cache.size();i++){ Node n = cache.get(i); if(!n.isParentCollapsed()||n.isRoot())//凡是父节点不收缩或者不是根节点的都挂上去 all.add(n); } } @Override public int getCount() { // TODO Auto-generated method stub return all.size(); } @Override public Object getItem(int location) { // TODO Auto-generated method stub return all.get(location); } @Override public long getItemId(int location) { // TODO Auto-generated method stub return location; } @Override public View getView(final int location, View view, ViewGroup viewgroup) { final Node n = all.get(location); //ViewItem vi = null; if(view == null){ view = lif.inflate(R.layout.member_item, null); vi = new ViewItem(); vi.cb = (CheckBox)view.findViewById(R.id.checkBox); vi.flagIcon = (ImageView)view.findViewById(R.id.disclosureImg); vi.tv = (TextView)view.findViewById(R.id.contentText); vi.cb.setOnClickListener(new OnClickListener() { private Node mCheckBoxN; @Override public void onClick(View v) { mCheckBoxN = (Node) v.getTag(); checkNode(mCheckBoxN, ((CheckBox) v).isChecked()); //unCheckNode(n, ((CheckBox) v).isChecked()); tree.notifyDataSetChanged(); //只有点击部门后刷新页面,不然刷新频繁导致卡顿 } }); view.setTag(vi); } else{ vi = (ViewItem)view.getTag(); } if(n!=null){ if(vi==null||vi.cb==null) System.out.println(); vi.cb.setTag(n); vi.cb.setChecked(n.isChecked()); //叶节点不显示展开收缩图标 if(n.isExplaned()){ if(expandIcon!=-1){ vi.flagIcon.setImageResource(expandIcon); } } else{ if(collapseIcon!=-1){ vi.flagIcon.setImageResource(collapseIcon); } } //显示文本 vi.tv.setText(n.getValue()); // 控制缩进 vi.flagIcon.setPadding(100*n.getLevel(), 3,3, 3); if(n.isLeaf()){ vi.flagIcon.setVisibility(View.INVISIBLE); } else{ vi.flagIcon.setVisibility(View.VISIBLE); } //设置是否显示复选框 if(n.hasCheckBox()){ vi.cb.setVisibility(View.VISIBLE); } else{ vi.cb.setVisibility(View.GONE); } } return view; } public class ViewItem{ private CheckBox cb; private ImageView flagIcon; private TextView tv; } }

接下来是TreeListView: 

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package com.example.administrator.treeview.treeView; import android.content.Context; import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.RelativeLayout; import com.example.administrator.treeview.R; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; public class TreeListView extends ListView { ListView treelist = null; TreeAdapter ta = null; public List<Node> mNodeList; private List<Node> checkList; public TreeListView(final Context context, List<Node> res) { super(context); treelist = this; treelist.setFocusable(false); treelist.setBackgroundColor(0xffffff); treelist.setFadingEdgeLength(0); treelist.setLayoutParams(new ViewGroup.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT)); treelist.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { ((TreeAdapter) parent.getAdapter()).ExpandOrCollapse(position); } }); initNode(context, initNodRoot(res), true, -1, -1, 0); } // 使用 onMeasure 方法,来解决尺寸高度的问题,以及事件冲突的问题; protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { heightMeasureSpec = MeasureSpec.makeMeasureSpec( Integer.MAX_VALUE>>2, MeasureSpec.AT_MOST ); super.onMeasure(widthMeasureSpec, heightMeasureSpec); } // /** // * // * @param context // * 响应监听的上下文 // * @param root // * 已经挂好树的根节点 // * @param hasCheckBox // * 是否整个树有复选框 // * @param tree_ex_id // * 展开iconid -1会使用默认的 // * @param tree_ec_id // * 收缩iconid -1会使用默认的 // * @param expandLevel // * 初始展开等级 // * // */ public List<Node> initNodRoot(List<Node> res) { ArrayList<Node> list = new ArrayList<Node>(); ArrayList<Node> roots = new ArrayList<Node>(); Map<String, Node> nodemap = new LinkedHashMap<String, Node>(); for (int i = 0; i < res.size(); i++) { Node nr = res.get(i); Node n = new Node( nr.getParentId(), nr.getCurId(), nr.getValue()); nodemap.put(n.getCurId(), n);// 生成map树 } Set<String> set = nodemap.keySet(); Collection<Node> collections = nodemap.values(); Iterator<Node> iterator = collections.iterator(); while (iterator.hasNext()) {// 添加所有根节点到root中 Node n = iterator.next(); if (!set.contains(n.getParentId())) roots.add(n); list.add(n); } for (int i = 0; i < list.size(); i++) { Node n = list.get(i); for (int j = i + 1; j < list.size(); j++) { Node m = list.get(j); if (m.getParentId() .equals( n.getCurId())) { n.addNode(m); m.setParent(n); m.setParents(n); } else if (m.getCurId() .equals( n.getParentId())) { m.addNode(n); n.setParent(m); m.setParents(m); } } } return roots; } public void initNode(Context context, List<Node> root, boolean hasCheckBox, int tree_ex_id, int tree_ec_id, int expandLevel) { ta = new TreeAdapter(context, root); //获取 mNodeList = ta.all; // 设置整个树是否显示复选框 ta.setCheckBox(true); // 设置展开和折叠时图标 int tree_ex_id_ = (tree_ex_id == -1) ? R.drawable.down_icon : tree_ex_id; int tree_ec_id_ = (tree_ec_id == -1) ? R.drawable.right_icon : tree_ec_id; ta.setCollapseAndExpandIcon(tree_ex_id_, tree_ec_id_); // 设置默认展开级别 ta.setExpandLevel(expandLevel); this.setAdapter(ta); } /* 返回当前所有选中节点的List数组 */ public List<Node> get() { Log.d("get", ta.getSelectedNode().size() + ""); return ta.getSelectedNode(); } public void setSelect(List<String> allSelect){ ta.setSelectedNode(allSelect); }}

资源地址:Android带复选框的树形组织架构treeListView

github链接:treeListView

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持靠谱客。

最后

以上就是仁爱咖啡豆最近收集整理的关于Android TreeView实现带复选框树形组织结构的全部内容,更多相关Android内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(118)

评论列表共有 0 条评论

立即
投稿
返回
顶部