Android treeview implements a tree organization structure with check boxes

Previously, it was used in the project and in the personnel organization structure. It can also be used in the directory view. After a simple search, there was no suitable one. Only a basic flawed tree structure was found. On the basis, it was changed, a check box was added and part of the code was simplified. The following is a demonstration of the effect picture, which lasts 25 seconds. Sorry for the mobile card.

Check boxes have two design modes:

1. If the child node is selected, the parent node is selected. It is suitable for multi-level and multiple items to understand which are selected;

2. Select all child nodes before selecting the parent node, which is more in line with daily logic and suitable for less quantity and less level.

The main codes are as follows:

First, the mainactivity is used to load layout and read data. In practice, it is generally obtained from the database. Sorry for the casual naming.

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

Next is the node class:

Currently, node objects are mainly composed of parent node ID, self ID and value. Self ID is added and parent node ID is added. During use, member attributes are added according to actual use. For example, as an organizational structure, whether the identification is a person's name or an empty department, what level the current object is, etc., and when it is obtained from the database, it is directly set to be selected by default.

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 hasCheck@R_274_2419@ = 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 hasCheck@R_274_2419@() {
 return hasCheck@R_274_2419@;
 }
 /**
 * 设置是否有复选框
 * @param hasCheck@R_274_2419@
 *
 */
 public void setHasCheck@R_274_2419@(boolean hasCheck@R_274_2419@) {
 this.hasCheck@R_274_2419@ = hasCheck@R_274_2419@;
 }

 /**
 * 得到节点值
 * @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;
 }
}

Here is the core code:

The two selection modes are modified in treeadapter.

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.Check@R_274_2419@;
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 hasCheck@R_274_2419@;
 private int expandIcon = -1;//展开图标
 private int collapseIcon = -1;//收缩图标
 ViewItem vi = null;

// //存储check@R_274_2419@选中的集合
// 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 hasCheck@R_274_2419@
 *
 */
 public void setCheck@R_274_2419@(boolean hasCheck@R_274_2419@){
 this.hasCheck@R_274_2419@ = hasCheck@R_274_2419@;
 }
 /**
 * 控制展开缩放某节点
 * @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 = (Check@R_274_2419@)view.findViewById(R.id.check@R_274_2419@);
 vi.flagIcon = (ImageView)view.findViewById(R.id.disclosureImg);
 vi.tv = (TextView)view.findViewById(R.id.contentText);
 vi.cb.setOnClickListener(new OnClickListener() {
 private Node mCheck@R_274_2419@N;
 @Override
 public void onClick(View v) {
 mCheck@R_274_2419@N = (Node) v.getTag();
 checkNode(mCheck@R_274_2419@N,((Check@R_274_2419@) v).isChecked());
 //unCheckNode(n,((Check@R_274_2419@) 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);
 if(n.isLeaf()){
 vi.flagIcon.setVisibility(View.INVISIBLE);
 }
 else{
 vi.flagIcon.setVisibility(View.VISIBLE);
 }
 //设置是否显示复选框
 if(n.hasCheck@R_274_2419@()){
 vi.cb.setVisibility(View.VISIBLE);
 }
 else{
 vi.cb.setVisibility(View.GONE);
 }
 }
 return view;
 }

 public class ViewItem{
 private Check@R_274_2419@ cb;
 private ImageView flagIcon;
 private TextView tv;
 }
}

Next is treelistview:

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,int position,long id) {
 ((TreeAdapter) parent.getAdapter()).ExpandOrCollapse(position);
 }
 });
 initNode(context,initNodRoot(res),true,-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 hasCheck@R_274_2419@
// * 是否整个树有复选框
// * @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 hasCheck@R_274_2419@,int tree_ex_id,int tree_ec_id,int expandLevel) {
 ta = new TreeAdapter(context,root);
 //获取
 mNodeList = ta.all;
 // 设置整个树是否显示复选框
 ta.setCheck@R_274_2419@(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);
}}

Resource address: tree organization treelistview with check box for Android

GitHub link: treelistview

The above is the whole content of this article. I hope it will help you in your study, and I hope you will support us a lot.

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>