Android:任意层级树形控件(有效果图和Demo示例)

先上效果图:

1.创建treeview文件夹

2.treeview -> adapter -> SimpleTreeAdapter.java 

import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.TextView;import com.ybgc.acceptanceofconcealedwork.R;
import com.ybgc.acceptanceofconcealedwork.divview.treeview.treebean.Node;
import com.ybgc.acceptanceofconcealedwork.divview.treeview.treebean.TreeListViewAdapter;import java.util.List;public class SimpleTreeAdapter<T> extends TreeListViewAdapter<T> {//    private int mCurrentItem = -1;private ViewHolder viewHolder = null;private Context mContext;public SimpleTreeAdapter(ListView mTree, Context context, List<T> datas,int defaultExpandLevel) throws IllegalArgumentException,IllegalAccessException {super(mTree, context, datas, defaultExpandLevel);mContext = context;}@Overridepublic View getConvertView(Node node, int position, View convertView, ViewGroup parent) {if (convertView == null) {convertView = mInflater.inflate(R.layout.list_item, parent, false);viewHolder = new ViewHolder();viewHolder.icon = convertView.findViewById(R.id.id_treenode_icon);viewHolder.label = convertView.findViewById(R.id.id_treenode_label);viewHolder.rlSelectItem = convertView.findViewById(R.id.rlSelectItem);convertView.setTag(viewHolder);} else {viewHolder = (ViewHolder) convertView.getTag();}if (node.getIcon() == -1) {viewHolder.icon.setVisibility(View.INVISIBLE);} else {viewHolder.icon.setVisibility(View.VISIBLE);viewHolder.icon.setImageResource(node.getIcon());}viewHolder.label.setText(node.getName());return convertView;}private final class ViewHolder {private ImageView icon;private TextView label;private RelativeLayout rlSelectItem;}
}

3.treeview -> treebean

3.1.treeview -> treebean -> Node.java

import java.util.ArrayList;
import java.util.List;public class Node
{private String id;/*** 根节点pId为0*/private String pId = "0";private String name;/*** 当前的级别*/private int level;/*** 是否展开*/private boolean isExpand = false;private int icon;/*** 下一级的子Node*/private List<Node> children = new ArrayList<Node>();/*** 父Node*/private Node parent;public Node(){}public Node(String id, String pId, String name){super();this.id = id;this.pId = pId;this.name = name;}public int getIcon(){return icon;}public void setIcon(int icon){this.icon = icon;}public String getId(){return id;}public void setId(String id){this.id = id;}public String getpId(){return pId;}public void setpId(String 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;}/*** 是否为跟节点* * @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);}}}}

3.2.treeview -> treebean -> TreeHelper.java

import com.ybgc.acceptanceofconcealedwork.R;
import com.ybgc.acceptanceofconcealedwork.util.LogUtil;import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;public class TreeHelper {/*** 传入我们的普通bean,转化为我们排序后的Node** @param datas* @param defaultExpandLevel* @return* @throws IllegalArgumentException* @throws IllegalAccessException*/public static <T> List<Node> getSortedNodes(List<T> datas,int defaultExpandLevel) {List<Node> result = new ArrayList<Node>();try {// 将用户数据转化为List<Node>List<Node> nodes = convetData2Node(datas);// 拿到根节点List<Node> rootNodes = getRootNodes(nodes);// 排序以及设置Node间关系for (Node node : rootNodes) {addNode(result, node, defaultExpandLevel, 1);}} catch (Exception e) {LogUtil.e(e.toString());}return result;}/*** 过滤出所有可见的Node** @param nodes* @return*/public static List<Node> filterVisibleNode(List<Node> nodes) {List<Node> result = new ArrayList<Node>();try {for (Node node : nodes) {// 如果为跟节点,或者上层目录为展开状态if (node.isRoot() || node.isParentExpand()) {setNodeIcon(node);result.add(node);}}} catch (Exception e) {LogUtil.e(e.toString());}return result;}/*** 将我们的数据转化为树的节点** @param datas* @return* @throws NoSuchFieldException* @throws IllegalAccessException* @throws IllegalArgumentException*/private static <T> List<Node> convetData2Node(List<T> datas) {List<Node> nodes = new ArrayList<Node>();Node node = null;try {for (T t : datas) {String id = "-1";String pId = "-1";String label = null;Class<? extends Object> clazz = t.getClass();Field[] declaredFields = clazz.getDeclaredFields();for (Field f : declaredFields) {if (f.getAnnotation(TreeNodeId.class) != null) {f.setAccessible(true);id = String.valueOf(f.get(t));}if (f.getAnnotation(TreeNodePid.class) != null) {f.setAccessible(true);pId = String.valueOf(f.get(t));}if (f.getAnnotation(TreeNodeLabel.class) != null) {f.setAccessible(true);label = (String) f.get(t);}if (!id.equals("-1") && !pId.equals("-1") && label != null) {break;}}node = new Node(id, pId, label);nodes.add(node);}/*** 设置Node间,父子关系;让每两个节点都比较一次,即可设置其中的关系*/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().equals(n.getId())) {n.getChildren().add(m);m.setParent(n);} else if (m.getId().equals(n.getpId())) {m.getChildren().add(n);n.setParent(m);}}}// 设置图片for (Node n : nodes) {setNodeIcon(n);}} catch (Exception e) {LogUtil.e(e.toString());}return nodes;}private static List<Node> getRootNodes(List<Node> nodes) {List<Node> root = new ArrayList<Node>();try {for (Node node : nodes) {if (node.isRoot())root.add(node);}} catch (Exception e) {LogUtil.e(e.toString());}return root;}/*** 把一个节点上的所有的内容都挂上去*/private static void addNode(List<Node> nodes, Node node,int defaultExpandLeval, int currentLevel) {try {nodes.add(node);if (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);}} catch (Exception e) {LogUtil.e(e.toString());}}/*** 设置节点的图标** @param node*/private static void setNodeIcon(Node node) {try {if (node.getChildren().size() > 0 && node.isExpand()) {node.setIcon(R.mipmap.tree_ex);//设置展开状态图标} else if (node.getChildren().size() > 0 && !node.isExpand()) {node.setIcon(R.mipmap.tree_ec);//设置未展开状态图标} else {node.setIcon(-1);}} catch (Exception e) {LogUtil.e(e.toString());}}}

3.3.treeview -> treebean -> TreeListViewAdapter.java

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.ListView;import java.util.List;public abstract class TreeListViewAdapter<T> extends BaseAdapter
{protected Context mContext;/*** 存储所有可见的Node*/protected List<Node> mNodes;protected LayoutInflater mInflater;/*** 存储所有的Node*/protected List<Node> mAllNodes;/*** 点击的回调接口*/private OnTreeNodeClickListener onTreeNodeClickListener;public interface OnTreeNodeClickListener{void onClick(Node node, int position);}public void setOnTreeNodeClickListener(OnTreeNodeClickListener onTreeNodeClickListener){this.onTreeNodeClickListener = onTreeNodeClickListener;}/*** * @param mTree* @param context* @param datas* @param defaultExpandLevel*            默认展开几级树* @throws IllegalArgumentException* @throws IllegalAccessException*/public TreeListViewAdapter(ListView mTree, Context context, List<T> datas,int defaultExpandLevel) throws IllegalArgumentException,IllegalAccessException{mContext = context;/*** 对所有的Node进行排序*/mAllNodes = TreeHelper.getSortedNodes(datas, defaultExpandLevel);/*** 过滤出可见的Node*/mNodes = TreeHelper.filterVisibleNode(mAllNodes);mInflater = LayoutInflater.from(context);/*** 设置节点点击时,可以展开以及关闭;并且将ItemClick事件继续往外公布*/mTree.setOnItemClickListener(new OnItemClickListener(){@Overridepublic void onItemClick(AdapterView<?> parent, View view,int position, long id){expandOrCollapse(position);if (onTreeNodeClickListener != null){onTreeNodeClickListener.onClick(mNodes.get(position),position);}}});}/*** 相应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();// 刷新视图}}}@Overridepublic int getCount(){return mNodes.size();}@Overridepublic Object getItem(int position){return mNodes.get(position);}@Overridepublic long getItemId(int position){return position;}@Overridepublic View getView(int position, View convertView, ViewGroup parent){Node node = mNodes.get(position);convertView = getConvertView(node, position, convertView, parent);// 设置内边距convertView.setPadding(node.getLevel() * 30, 3, 3, 3);return convertView;}public abstract View getConvertView(Node node, int position,View convertView, ViewGroup parent);}

3.4.treeview -> treebean -> TreeNodeId.java

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TreeNodeId
{
}

3.5.treeview -> treebean -> TreeNodeLabel.java

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TreeNodeLabel
{}

3.6.treeview -> treebean -> TreeNodePid.java

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TreeNodePid
{}

4.treeview -> bean

4.1.treeview -> bean -> FileBean.java

import com.ybgc.acceptanceofconcealedwork.divview.treeview.treebean.TreeNodeAcode;
import com.ybgc.acceptanceofconcealedwork.divview.treeview.treebean.TreeNodeId;
import com.ybgc.acceptanceofconcealedwork.divview.treeview.treebean.TreeNodeLabel;
import com.ybgc.acceptanceofconcealedwork.divview.treeview.treebean.TreeNodePid;public class FileBean
{@TreeNodeIdprivate String id;@TreeNodePidprivate String parentId;@TreeNodeLabelprivate String name;private long length;private String desc;public FileBean(String id, String parentId, String name,String acode){super();this.id = id;this.parentId = parentId;this.name = name;}}

5.layout布局文件

5.1.activity_main.xml 主文件布局(ListView就是树形控件的载体)

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent" ><ListViewandroid:id="@+id/id_tree"android:layout_width="fill_parent"android:layout_height="fill_parent"android:divider="#aaa"android:dividerHeight="1px" ></ListView></RelativeLayout>

5.2.ListView 的子布局list_item.xml(树形控件的子布局,里面的图片就是用来展示树形控件打开状态和关闭状态的图片)

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="fill_parent"android:layout_height="wrap_content"android:minHeight="40dip" ><ImageViewandroid:id="@+id/id_treenode_icon"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerVertical="true"android:layout_marginLeft="5dp"android:layout_marginRight="5dp"android:src="@drawable/tree_ec" /><TextViewandroid:id="@+id/id_treenode_label"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerVertical="true"android:layout_toRightOf="@id/id_treenode_icon"android:text="@string/app_name"android:textSize="18dip" /></RelativeLayout>

6.上面树形控件代码已经完成,下面是页面中使用

import java.util.ArrayList;
import java.util.List;public class MainActivity extends AppCompatActivity {private List<FileBean> mDatas = new ArrayList<FileBean>();private ListView mTree;private TreeListViewAdapter mAdapter;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initDatas();mTree = findViewById(R.id.id_tree);try {//适配器参数:tree控件,上下文,数据源,默认展开层级mAdapter = new SimpleTreeAdapter<FileBean>(mTree, this, mData, 0);//初始化适配器mAdapter.setOnTreeNodeClickListener(new TreeListViewAdapter.OnTreeNodeClickListener() {//点击事件监听@Overridepublic void onClick(Node node, int position) {if (node.isLeaf()) {Toast.makeText(getApplicationContext(), node.getName(),Toast.LENGTH_SHORT).show();}}});} catch (Exception e) {e.printStackTrace();}mTree.setAdapter(mAdapter);//设置数据}/*** 初始化数据*/private void initData() {mDatas.add(new FileBean("1", "0", "文件管理系统"));mDatas.add(new FileBean("2", "1", "游戏"));mDatas.add(new FileBean("3", "1", "文档"));mDatas.add(new FileBean("4", "1", "程序"));mDatas.add(new FileBean("5", "2", "使命召唤"));mDatas.add(new FileBean("6", "2", "绝地求生"));mDatas.add(new FileBean("7", "4", "面向对象"));mDatas.add(new FileBean("8", "4", "非面向对象"));mDatas.add(new FileBean("9", "7", "C++"));mDatas.add(new FileBean("10", "7", "JAVA"));mDatas.add(new FileBean("11", "7", "Javascript"));mDatas.add(new FileBean("12", "8", "C"));mDatas.add(new FileBean("13", "3", "测试文档1"));mDatas.add(new FileBean("14", "3", "测试文档2"));}
}

以上就是自定义树形控件的所有代码,希望对大家的学习和工作有所帮助。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/19965.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

Jmeter中的断言(四)

13--XPath断言 功能特点 数据验证&#xff1a;验证 XML 响应数据是否包含或不包含特定的字段或值。支持 XPath 表达式&#xff1a;使用 XPath 表达式定位和验证 XML 数据中的字段。灵活配置&#xff1a;可以设置多个断言条件&#xff0c;满足复杂的测试需求。 配置步骤 添加…

3243.新增道路查询的最短距离

给你一个整数 n 和一个二维整数数组 queries。 有 n 个城市&#xff0c;编号从 0 到 n - 1。初始时&#xff0c;每个城市 i 都有一条单向道路通往城市 i 1&#xff08; 0 < i < n - 1&#xff09;。 queries[i] [ui, vi] 表示新建一条从城市 ui 到城市 vi 的单向道路…

MySQL - 表的约束

文章目录 1、空约束2.默认值3.列描述4.zerofill5.主键6.自增长7.唯一键8.外键 真正约束字段的是数据类型&#xff0c;但是数据类型约束很单一&#xff0c;需要有一些额外的约束&#xff0c;更好的保证数据的合法性&#xff0c;从业务逻辑角度保证数据的正确性。比如有一个字段是…

VirtualBox安装虚拟机Windows server 2019系统只显示cmd命令窗口

原因&#xff1a; 没注意选用了核心安装选项&#xff0c;此选项不安装图形界面 解决&#xff1a; 方式一&#xff1a;重装虚拟机&#xff0c;选用有图形界面的版本 方式二&#xff1a;在cmd窗口中安装图形界面 Dism /online /enable-feature /all /featurename:Server-Gui-Mgm…

基于卷积神经网络的皮肤病识别系统(pytorch框架,python源码,GUI界面,前端界面)

更多图像分类、图像识别、目标检测等项目可从主页查看 功能演示&#xff1a; 皮肤病识别系统 vgg16 resnet50 卷积神经网络 GUI界面 前端界面&#xff08;pytorch框架 python源码&#xff09;_哔哩哔哩_bilibili &#xff08;一&#xff09;简介 基于卷积神经网络的皮肤病识…

MixVpr重定位实战----onnx以及Tensorrt适配

0. 简介 对于深度学习而言&#xff0c;通过模型加速来嵌入进C是非常有意义的&#xff0c;因为本身训练出来的pt文件其实效率比较低下&#xff0c;在讲完BEVDET和FastBEV后&#xff0c;这里我们将展开实战&#xff0c;从pt到onnx再到tensorrt&#xff0c;以MixVpr作为例子&…

Java基于微信小程序的校园跑腿平台(V2.0)

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

Spring Boot图书馆管理系统:疫情中的管理利器

摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了疫情下图书馆管理系统的开发全过程。通过分析疫情下图书馆管理系统管理的不足&#xff0c;创建了一个计算机管理疫情下图书馆管理系统的方案。文章介绍了疫情下图…

【CUDA】Branch Divergence and Unrolling Loop

目录 一、避免分支发散 1.1 并行规约问题 1.2 并行规约中的发散 二、UNrolling Loops 一、避免分支发散 控制流有时依赖于 thread 索引。同一个warp中&#xff0c;一个条件分支可能导致性能很差。通过重新组织数据获取模式可以减少或避免 warp divergence。具体问题查看下…

WIN系统解决小喇叭红色叉号的办法

WIN系统解决小喇叭红色叉号的办法 WIN系统提示无音频设备&#xff0c;无法播放声音&#xff0c;重装驱动无法解决 写在前面 前段时间搞了套6750GRE&#xff0c;用了两三个月&#xff0c;老是掉驱动&#xff0c;后面折腾了一下子&#xff0c;终于是不掉了。突然&#xff0c;某…

免费S3客户端工具大赏

首发地址&#xff08;欢迎大家访问&#xff09;&#xff1a;S3免费客户端工具大赏 1. S3 GUI GitHub地址&#xff1a;https://github.com/aminalaee/s3gui 简介&#xff1a;S3 GUI 是一款基于 Flutter 构建的免费开源 S3 桌面客户端&#xff0c;支持桌面、移动和网络平台。 特…

uniapp 购物弹窗组件 (微信小程序)

效果图&#xff0c;暂时只适应单规格&#xff0c;居中弹出和下方弹出&#xff0c;如需求不满足&#xff0c;请自行修改代码 &#xff08;更新于24/11/15) 居中显示效果 下方弹出效果 html <template><view class"" v-if"show":class"mod…

力扣-Mysql-1811 - 寻找面试候选人(中等)

一、题目来源 1811. 寻找面试候选人 - 力扣&#xff08;LeetCode&#xff09; 二、数据表结构 表: Contests -------------------- | Column Name | Type | -------------------- | contest_id | int | | gold_medal | int | | silver_medal | int | | bronze_medal | …

【C语言】volatile 防止编译的时候被优化

volatile 易变的 volatile是 C 和 C 中的一个类型修饰符&#xff0c;用于指示编译器该变量可能在程序之外被更改&#xff0c;因此不应对其进行优化。这在涉及硬件寄存器、信号处理或多线程编程时非常有用。 如果你做过单片机开发&#xff0c;你肯定写过这样的代码&#xff1a;…

makefile速通

makefile速通 文章目录 makefile速通1.基础显式规则隐含规则%*通配符 赋值 伪目标CFLAGS 2.函数wildcardpatsubst 3.项目实例 1.基础 显式规则 目标文件&#xff1a;依赖文件 [TAB] 指令隐含规则 % 任意* 所有通配符 符号含义$^所有依赖文件$所有目标文件$<所有依赖文…

面向服务的软件工程——巨详细讲解商务流程建模符号 (BPMN),一篇章带你入门BPMN!!!(week1)

文章目录 一、前言二、重点概念三、BPMN元素讲解流对象1.活动任务(Task)子流程(sub-process)多实例活动连接对象序列流消息流关联泳道Artifacts数据对象组(Group)事件(Events)启动事件中间事件结束事件边界事件边界事件1边界事件2小疑问?网关参考文献:一、前言 在我们…

模拟实现~简易通讯录

一.前言 今天给小伙伴们分享的是运用结构体以及指针等相关C语言知识实现一个简易版的通讯录。咱们写的通讯录的功能主要包括添加及删除联系人&#xff0c;修改联系人信息&#xff0c;显现所有联系人&#xff0c;查找已添加联系人&#xff0c;以及对联系人进行排序&#xff0c;…

0成本添加访问级监控

互联网的安全感这个概念源于阿里。顾名思义&#xff0c;让互联网的用户对于web产品能够产生足够的信任和依赖。特别是涉及到用户资金交易的站点&#xff0c;一次严重的用户资料泄露就可以彻底毁掉你的品牌。 然而当前阶段除了bat大部分互联网行业的企业对于网络安全给的重视都…

分布式系统稳定性建设-性能优化篇

分布式系统稳定性建设-性能优化篇 系统稳定性建设是系统工程的核心内容之一。以下是一些重要的方面: 架构设计: 采用模块化、松耦合的架构设计,以提高系统的可扩展性和可维护性。合理划分系统功能模块,降低单个模块的复杂度。定义清晰的接口和数据交换标准,确保各模块之间协调…

Web端高效BIM 3D可视化引擎HOOPS Communicator技术解析!

HOOPS Communicator是一款简单而强大的工业级高性能3D Web可视化开发包&#xff0c;专注于Web端工程图形渲染。采用了先进的流式加载方式&#xff0c;并支持服务端和客户端渲染&#xff0c;是可以在云端进行部署和无缝集成的新技术平台。 灵活且易于部署&#xff0c;可在以工程…