返回顶部
首页 > 资讯 > 移动开发 >Android多级树形列表控件
  • 923
分享到

Android多级树形列表控件

列表Android 2022-06-06 05:06:20 923人浏览 安东尼
摘要

我们开发app过程中,经常会碰到需要 多级列表展示的效果。而Android原生sdk中根本没有3级 4级甚至更多级别的列表控件。 所以我们就要自己去实现一个类似treeList

我们开发app过程中,经常会碰到需要 多级列表展示的效果。而Android原生sdk中根本没有3级 4级甚至更多级别的列表控件。
所以我们就要自己去实现一个类似treeListView 的控件,下面这个是我项目中的一个效果图,可支持多级列表扩展。

  

android中有ExpandListView控件,但是这个控件只支持两级列表。对于多级列表如果重写这个不是很好用。
实现这种列表 思想就是递归,构造一个子父级的关系。
话不多说 代码中体会
Activity


package com.example.customtreeviewdemo; 
import java.util.ArrayList; 
import java.util.List; 
import android.app.Activity; 
import android.os.Bundle; 
import android.view.View; 
import android.view.View.OnClickListener; 
import android.widget.Button; 
import android.widget.ListView; 
import android.widget.Toast; 
import com.example.customtreeviewdemo.bean.MynodeBean; 
import com.example.customtreeviewdemo.tree.Node; 
import com.example.customtreeviewdemo.tree.TreeListViewAdapter.OnTreeNodeClickListener; 
public class MainActivity extends Activity { 
  private ListView treeLv; 
  private Button checkSwitchBtn; 
  private MyTreeListViewAdapter<MyNodeBean> adapter; 
  private List<MyNodeBean> mDatas = new ArrayList<MyNodeBean>(); 
  //标记是显示Checkbox还是隐藏 
  private boolean isHide = true; 
  @Override 
  protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_main); 
    initDatas(); 
    treeLv = (ListView) this.findViewById(R.id.tree_lv); 
    checkSwitchBtn = (Button)this.findViewById(R.id.check_switch_btn); 
    checkSwitchBtn.setOnClickListener(new OnClickListener(){ 
      @Override 
      public void onClick(View v) { 
        if(isHide){ 
          isHide = false; 
        }else{ 
          isHide = true; 
        } 
        adapter.updateView(isHide); 
      } 
    }); 
    try { 
      adapter = new MyTreeListViewAdapter<MyNodeBean>(treeLv, this, 
          mDatas, 10, isHide); 
      adapter.setOnTreeNodeClickListener(new OnTreeNodeClickListener() { 
        @Override 
        public void onClick(Node node, int position) { 
          if (node.isLeaf()) { 
            Toast.makeText(getApplicationContext(), node.getName(), 
                Toast.LENGTH_SHORT).show(); 
          } 
        } 
        @Override 
        public void onCheckChange(Node node, int position, 
            List<Node> checkedNodes) { 
          StringBuffer sb = new StringBuffer(); 
          for (Node n : checkedNodes) { 
            int pos = n.getId() - 1; 
            sb.append(mDatas.get(pos).getName()).append("---") 
                .append(pos + 1).append(";"); 
          } 
          Toast.makeText(getApplicationContext(), sb.toString(), 
              Toast.LENGTH_SHORT).show(); 
        } 
      }); 
    } catch (IllegalArgumentException e) { 
      e.printStackTrace(); 
    } catch (IllegalAccessException e) { 
      e.printStackTrace(); 
    } 
    treeLv.setAdapter(adapter); 
  } 
  private void initDatas() { 
    mDatas.add(new MyNodeBean(1, 0, "中国古代")); 
    mDatas.add(new MyNodeBean(2, 1, "唐朝")); 
    mDatas.add(new MyNodeBean(3, 1, "宋朝")); 
    mDatas.add(new MyNodeBean(4, 1, "明朝")); 
    mDatas.add(new MyNodeBean(5, 2, "李世民")); 
    mDatas.add(new MyNodeBean(6, 2, "李白")); 
    mDatas.add(new MyNodeBean(7, 3, "赵匡胤")); 
    mDatas.add(new MyNodeBean(8, 3, "苏轼")); 
    mDatas.add(new MyNodeBean(9, 4, "朱元璋")); 
    mDatas.add(new MyNodeBean(10, 4, "唐伯虎")); 
    mDatas.add(new MyNodeBean(11, 4, "文征明")); 
    mDatas.add(new MyNodeBean(12, 7, "赵建立")); 
    mDatas.add(new MyNodeBean(13, 8, "苏东东")); 
    mDatas.add(new MyNodeBean(14, 10, "秋香")); 
  } 
} 

Adapter
这个adapter是继承了自己的定义的一个TreeListViewAdapter,核心实现都是在TreeListViewAdapter这个里面


package com.example.customtreeviewdemo; 
import java.util.List; 
import android.content.Context; 
import android.view.View; 
import android.view.ViewGroup; 
import android.widget.CheckBox; 
import android.widget.CompoundButton; 
import android.widget.CompoundButton.OnCheckedChangeListener; 
import android.widget.ImageView; 
import android.widget.ListView; 
import android.widget.TextView; 
import com.example.customtreeviewdemo.tree.Node; 
import com.example.customtreeviewdemo.tree.TreeListViewAdapter; 
public class MyTreeListViewAdapter<T> extends TreeListViewAdapter<T> { 
  public MyTreeListViewAdapter(ListView mTree, Context context, 
      List<T> datas, int defaultExpandLevel,boolean isHide) 
      throws IllegalArgumentException, IllegalAccessException { 
    super(mTree, context, datas, defaultExpandLevel,isHide); 
  } 
  @SuppressWarnings("unchecked") 
  @Override 
  public View getConvertView(Node node, int position, View convertView, 
      ViewGroup parent) { 
    ViewHolder viewHolder = null; 
    if (convertView == null) 
    { 
      convertView = mInflater.inflate(R.layout.list_item, parent, false); 
      viewHolder = new ViewHolder(); 
      viewHolder.icon = (ImageView) convertView 
          .findViewById(R.id.id_treenode_icon); 
      viewHolder.label = (TextView) convertView 
          .findViewById(R.id.id_treenode_name); 
      viewHolder.checkBox = (CheckBox)convertView.findViewById(R.id.id_treeNode_check); 
      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()); 
    } 
    if(node.isHideChecked()){ 
      viewHolder.checkBox.setVisibility(View.GoNE); 
    }else{ 
      viewHolder.checkBox.setVisibility(View.VISIBLE); 
      setCheckBoxBg(viewHolder.checkBox,node.isChecked()); 
    } 
    viewHolder.label.setText(node.getName()); 
    return convertView; 
  } 
  private final class ViewHolder 
  { 
    ImageView icon; 
    TextView label; 
    CheckBox checkBox; 
  } 
   
  private void setCheckBoxBg(CheckBox cb,boolean isChecked){ 
    if(isChecked){ 
      cb.setBackgroundResource(R.drawable.check_box_bg_check); 
    }else{ 
      cb.setBackgroundResource(R.drawable.check_box_bg); 
    } 
  } 
} 

自定义TreeListViewAdapter  这个是整个树形结构的一个适配器,这里面主要是实现对Node节点的操作 点击,选中改变 更新等


package com.example.customtreeviewdemo.tree; 
import java.util.ArrayList; 
import java.util.List; 
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.CheckBox; 
import android.widget.CompoundButton; 
import android.widget.CompoundButton.OnCheckedChangeListener; 
import android.widget.ListView; 
import android.widget.RelativeLayout; 
 
public abstract class TreeListViewAdapter<T> extends BaseAdapter { 
  protected Context mContext; 
   
  protected List<Node> mNodes; 
  protected LayoutInflater mInflater; 
   
  protected List<Node> mAllNodes; 
   
  private OnTreeNodeClickListener onTreeNodeClickListener; 
  public interface OnTreeNodeClickListener { 
     
    void onClick(Node node, int position); 
     
    void onCheckChange(Node node, int position,List<Node> checkedNodes); 
  } 
  public void setOnTreeNodeClickListener( 
      OnTreeNodeClickListener onTreeNodeClickListener) { 
    this.onTreeNodeClickListener = onTreeNodeClickListener; 
  } 
   
  public TreeListViewAdapter(ListView mTree, Context context, List<T> datas, 
      int defaultExpandLevel, boolean isHide) 
      throws IllegalArgumentException, IllegalAccessException { 
    mContext = context; 
     
    mAllNodes = TreeHelper 
        .getSortedNodes(datas, defaultExpandLevel, isHide); 
     
    mNodes = TreeHelper.filterVisibleNode(mAllNodes); 
    mInflater = LayoutInflater.from(context); 
     
    mTree.setOnItemClickListener(new OnItemClickListener() { 
      @Override 
      public void onItemClick(AdapterView<?> parent, View view, 
          int position, long id) { 
        expandOrCollapse(position); 
        if (onTreeNodeClickListener != null) { 
          onTreeNodeClickListener.onClick(mNodes.get(position), 
              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(final int position, View convertView, ViewGroup parent) { 
    final Node node = mNodes.get(position); 
    convertView = getConvertView(node, position, convertView, parent); 
    // 设置内边距 
    convertView.setPadding(node.getLevel() * 30, 3, 3, 3); 
    if (!node.isHideChecked()) { 
      //获取各个节点所在的父布局 
      RelativeLayout myView = (RelativeLayout) convertView; 
      //父布局下的CheckBox 
      CheckBox cb = (CheckBox) myView.getChildAt(1); 
      cb.setOnCheckedChangeListener(new OnCheckedChangeListener(){ 
        @Override 
        public void onCheckedChanged(CompoundButton buttonView, 
            boolean isChecked) { 
          TreeHelper.setNodeChecked(node, isChecked); 
          List<Node> checkedNodes = new ArrayList<Node>(); 
          for(Node n:mAllNodes){ 
            if(n.isChecked()){ 
              checkedNodes.add(n); 
            } 
          } 
          onTreeNodeClickListener.onCheckChange(node,position,checkedNodes); 
          TreeListViewAdapter.this.notifyDataSetChanged(); 
        } 
      }); 
    } 
    return convertView; 
  } 
  public abstract View getConvertView(Node node, int position, 
      View convertView, ViewGroup parent); 
   
  public void updateView(boolean isHide){ 
    for(Node node:mAllNodes){ 
      node.setHideChecked(isHide); 
    } 
    this.notifyDataSetChanged(); 
  } 
} 

node 模型类


package com.example.customtreeviewdemo.bean; 
public class MyNodeBean { 
   
  private int id; 
   
  private int pId; 
   
  private String name; 
   
  private String desc; 
   
  private long length; 
  public MyNodeBean(int id, int pId, String name) { 
    super(); 
    this.id = id; 
    this.pId = pId; 
    this.name = name; 
  } 
  public int getId() { 
    return id; 
  } 
  public void setId(int id) { 
    this.id = id; 
  } 
  public int getPid() { 
    return pId; 
  } 
  public void setPid(int pId) { 
    this.pId = pId; 
  } 
  public String getName() { 
    return name; 
  } 
  public void setName(String name) { 
    this.name = name; 
  } 
  public String getDesc() { 
    return desc; 
  } 
  public void setDesc(String desc) { 
    this.desc = desc; 
  } 
  public long getLength() { 
    return length; 
  } 
  public void setLength(long length) { 
    this.length = length; 
  } 
} 

TreeHelper这个也是核心操作类,主要功能是将业务数据和节点数据进行匹配


package com.example.customtreeviewdemo.tree; 
import java.lang.reflect.Field; 
import java.util.ArrayList; 
import java.util.List; 
import com.example.customtreeviewdemo.R; 
public class TreeHelper { 
   
  public static List<Node> filterVisibleNode(List<Node> allNodes) { 
    List<Node> visibleNodes = new ArrayList<Node>(); 
    for (Node node : allNodes) { 
      // 如果为根节点,或者上层目录为展开状态 
      if (node.isRoot() || node.isParentExpand()) { 
        setNodeIcon(node); 
        visibleNodes.add(node); 
      } 
    } 
    return visibleNodes; 
  } 
   
  public static <T> List<Node> getSortedNodes(List<T> datas, 
      int defaultExpandLevel, boolean isHide) 
      throws IllegalAccessException, IllegalArgumentException { 
    List<Node> sortedNodes = new ArrayList<Node>(); 
    // 将用户数据转化为List<Node> 
    List<Node> nodes = convertData2Nodes(datas, isHide); 
    // 拿到根节点 
    List<Node> rootNodes = getRootNodes(nodes); 
    // 排序以及设置Node间关系 
    for (Node node : rootNodes) { 
      addNode(sortedNodes, node, defaultExpandLevel, 1); 
    } 
    return sortedNodes; 
  } 
   
  private static void addNode(List<Node> nodes, Node node, 
      int defaultExpandLeval, int currentLevel) { 
    nodes.add(node); 
    if (defaultExpandLeval >= currentLevel) { 
      node.setExpand(true); 
    } 
    if (node.isLeaf()) 
      return; 
    for (int i = 0; i < node.getChildrenNodes().size(); i++) { 
      addNode(nodes, node.getChildrenNodes().get(i), defaultExpandLeval, 
          currentLevel + 1); 
    } 
  } 
   
  public static List<Node> getRootNodes(List<Node> nodes) { 
    List<Node> rootNodes = new ArrayList<Node>(); 
    for (Node node : nodes) { 
      if (node.isRoot()) { 
        rootNodes.add(node); 
      } 
    } 
    return rootNodes; 
  } 
   
  public static <T> List<Node> convertData2Nodes(List<T> datas, boolean isHide) 
      throws IllegalAccessException, IllegalArgumentException { 
    List<Node> nodes = new ArrayList<Node>(); 
    Node node = null; 
    for (T t : datas) { 
      int id = -1; 
      int pId = -1; 
      String name = null; 
      Class<? extends Object> clazz = t.getClass(); 
      Field[] declaredFields = clazz.getDeclaredFields(); 
       
      for (Field f : declaredFields) { 
        if ("id".equals(f.getName())) { 
          f.setAccessible(true); 
          id = f.getInt(t); 
        } 
        if ("pId".equals(f.getName())) { 
          f.setAccessible(true); 
          pId = f.getInt(t); 
        } 
        if ("name".equals(f.getName())) { 
          f.setAccessible(true); 
          name = (String) f.get(t); 
        } 
        if ("desc".equals(f.getName())) { 
          continue; 
        } 
        if ("length".equals(f.getName())) { 
          continue; 
        } 
        if (id == -1 && pId == -1 && name == null) { 
          break; 
        } 
      } 
      node = new Node(id, pId, name); 
      node.setHideChecked(isHide); 
      nodes.add(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 (n.getId() == m.getpId()) { 
          n.getChildrenNodes().add(m); 
          m.setParent(n); 
        } else if (n.getpId() == m.getId()) { 
          n.setParent(m); 
          m.getChildrenNodes().add(n); 
        } 
      } 
    } 
    for (Node n : nodes) { 
      setNodeIcon(n); 
    } 
    return nodes; 
  } 
   
  public static void setNodeIcon(Node node) { 
    if (node.getChildrenNodes().size() > 0 && node.isExpand()) { 
      node.setIcon(R.drawable.tree_expand); 
    } else if (node.getChildrenNodes().size() > 0 && !node.isExpand()) { 
      node.setIcon(R.drawable.tree_econpand); 
    } else 
      node.setIcon(-1); 
  } 
  public static void setNodeChecked(Node node, boolean isChecked) { 
    // 自己设置是否选择 
    node.setChecked(isChecked); 
     
    setChildrenNodeChecked(node, isChecked); 
     
    setParentNodeChecked(node); 
  } 
   
  private static void setChildrenNodeChecked(Node node, boolean isChecked) { 
    node.setChecked(isChecked); 
    if (!node.isLeaf()) { 
      for (Node n : node.getChildrenNodes()) { 
        // 所有子节点设置是否选择 
        setChildrenNodeChecked(n, isChecked); 
      } 
    } 
  } 
   
  private static void setParentNodeChecked(Node node) { 
     
    if (!node.isRoot()) { 
      Node rootNode = node.getParent(); 
      boolean isAllChecked = true; 
      for (Node n : rootNode.getChildrenNodes()) { 
        if (!n.isChecked()) { 
          isAllChecked = false; 
          break; 
        } 
      } 
      if (isAllChecked) { 
        rootNode.setChecked(true); 
      } else { 
        rootNode.setChecked(false); 
      } 
      setParentNodeChecked(rootNode); 
    } 
  } 
} 

核心的代码就是这些,希望对大家有帮助。

DEMO源码Http://xiazai.jb51.net/201611/yuanma/AndroidTreeView(jb51.net).rar

您可能感兴趣的文章:Android实现多级树形选择列表Android 绘制多级树形选择列表实例代码Android中RecyclerView实现多级折叠列表效果(二)Android中RecyclerView实现多级折叠列表效果(TreeRecyclerView)Android UI 之实现多级树形列表TreeView示例Android仿美团淘宝实现多级下拉列表菜单功能Android实现多级列表中的新建功能


--结束END--

本文标题: Android多级树形列表控件

本文链接: https://lsjlt.com/news/23191.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Android多级树形列表控件
    我们开发app过程中,经常会碰到需要 多级列表展示的效果。而Android原生sdk中根本没有3级 4级甚至更多级别的列表控件。 所以我们就要自己去实现一个类似treeList...
    99+
    2022-06-06
    列表 Android
  • android RecycleView实现多级树形列表
    本文实例为大家分享了android RecycleView实现多级树形列表的具体代码,供大家参考,具体内容如下 实现多级树状列表: 1. Node.java public cla...
    99+
    2024-04-02
  • android RecycleView如何实现多级树形列表
    这篇文章给大家分享的是有关android RecycleView如何实现多级树形列表的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。本文实例为大家分享了android RecycleView实现多级树形列表的具体代...
    99+
    2023-06-15
  • Android UI 之实现多级树形列表TreeView示例
    所谓TreeView就是在Windows中常见的多级列表树,在Android中系统只默认提供了ListView和ExpandableListView两种列表,最多只支持到二级列...
    99+
    2022-06-06
    treeview Android
  • VUE递归树形实现多级列表
    本文实例为大家分享了VUE递归树形实现多级列表,供大家参考,具体内容如下 什么是递归 简单来说就是在组件中内使用组件本身。 为什么要用递归? 如果出现很多下拉菜单,同级,分级数据,层...
    99+
    2024-04-02
  • VUE递归树形怎么实现多级列表
    今天小编给大家分享一下VUE递归树形怎么实现多级列表的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。什么是递归简单来说就是在组...
    99+
    2023-07-02
  • Android 开发中怎么利用TreeView实现一个多级树形列表
    今天就跟大家聊聊有关Android 开发中怎么利用TreeView实现一个多级树形列表,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。具体的实现思路参考下面的项目结构和具体代码:Ele...
    99+
    2023-05-31
    android treeview 多级树形列表
  • vue通过element树形控件实现树形表格
    目录实现效果图安装依赖自定义树形控件其他实现总结在vue中通过element树形控件来实现树形表格的效果 通过缩进来实现近似树形表格的效果 实现效果图 安装依赖 $ npm ins...
    99+
    2024-04-02
  • Python tkinter 树形列表控件(Treeview)的使用方法
    目录1.方法1.1 bbox(item, column=None) 1.2 column( cid, option=None, **kw) 1.3 delete(items...
    99+
    2024-04-02
  • Android树形控件绘制方法
    前言 作为一个开发者,日常会接触到很多优秀的软件,其实,或多或少会有这样的想法,我能不能开发一个自己软件,甚至办公软件都希望是Markdown的文本,为何用office?我常常...
    99+
    2022-06-06
    方法 Android
  • Android树形控件的实现方法
    在PC上我们已经习惯了树形控件,因为其可以清晰的展现各个节点之间的层次结果,但是在Android平台上,系统并没有提供这样一个控件,而是只有ListView。不过通过改写与Li...
    99+
    2022-06-06
    方法 Android
  • Android实现树形层级ListView
    直接贴代码,代码中有相应注释: 主界面Activity,布局就只一个ListView: public class MainActivity extends Activit...
    99+
    2022-06-06
    listview Android
  • JavaScript树形组件实现无限级树形结构
    目录​一、问题研究的背景和意义​​二、详细设计方案​​三、源代码实现(Java版)​​四、思考与总结​(1)XML层次结构(2)UL-LI层次结构(3)TABLE层次结构​一、问题研...
    99+
    2024-04-02
  • Android提高之多级树形菜单的实现方法
    一般来说在Android里要实现树形菜单,都是用ExpandableList(也有高手自己继承ListView或者LinearLayout来做),但是ExpandableLis...
    99+
    2022-06-06
    菜单 方法 Android
  • C#怎么实现树形图列表
    这篇“C#怎么实现树形图列表”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“C#怎么实现树形图列表”文章吧。效果代码publi...
    99+
    2023-07-04
  • ElementUI Tree树形控件怎么用
    小编给大家分享一下ElementUI Tree树形控件怎么用,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!一,数据渲染1)在&l...
    99+
    2024-04-02
  • vue树形控件tree怎么用
    这篇文章给大家分享的是有关vue树形控件tree怎么用的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。具体内容如下<template>  <div class=&qu...
    99+
    2023-06-29
  • 基于angular实现树形二级表格
    先看效果: 代码: 1、html <div class="userContent_content"> <div> <tab...
    99+
    2024-04-02
  • oracle表中树形结构与分级查询
    1.此处以emp表为例 此表中 empno 字段与 mgr 字段存在 下级与上级关系 2从上往下查 最顶级的boss 此处的level是三大伪列之一 级别select level...
    99+
    2024-04-02
  • vue树形控件tree的使用方法
    本文实例为大家分享了vue树形控件tree使用的具体代码,供大家参考,具体内容如下 <template>   <div class="hello tree-con...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作