所谓TreeView就是在Windows中常见的多级列表树,在Android中系统只默认提供了ListView和ExpandableListView两种列表,最多只支持到二级列表的实现,所以如果想要实现三级和更多层次的列表,就需要我们自己来做一些处理了。

    其实这个效果很久以前就有人想办法实现了,但是实现的效果有一些问题,我的实现思路主要也是来自于网络,但是在其基础上修正了逻辑上的一些错误,做了一些优化。

    先来看一下效果:

然后大体说一下思路:

    其实这里实现的多级列表只是一个视觉效果,我们看到的分级效果是由于每行的缩进不同造成的。比如在上面的效果中,山东省和广东省是级别最高的层次,山东省下的青岛市作为山东省的子项,我们增加他的左缩进,这样看起来就有了层次感了。其他的层次也是同理。

    也就是说,我们只用了一个ListView,工作的重点就在于不断变化ListView显示的数据,根据用户的操作,将数据修改为用户想要看到的数据内容,并根据每个数据项的不同,在显示效果上做不同的缩进处理,最终呈现出一个TreeView的效果。

    具体的实现思路参考下面的项目结构和具体代码:

Element.Java:

[java] view plaincopy
  1. package com.example.androidtreeviewdemo.treeview;
  2. /**
  3. * Element类
  4. * @author carrey
  5. *
  6. */
  7. public class Element {
  8. /** 文字内容 */
  9. private String contentText;
  10. /** 在tree中的层级 */
  11. private int level;
  12. /** 元素的id */
  13. private int id;
  14. /** 父元素的id */
  15. private int parendId;
  16. /** 是否有子元素 */
  17. private boolean hasChildren;
  18. /** item是否展开 */
  19. private boolean isExpanded;
  20. /** 表示该节点没有父元素,也就是level为0的节点 */
  21. public static final int NO_PARENT = -1;
  22. /** 表示该元素位于最顶层的层级 */
  23. public static final int TOP_LEVEL = 0;
  24. public Element(String contentText, int level, int id, int parendId,
  25. boolean hasChildren, boolean isExpanded) {
  26. super();
  27. this.contentText = contentText;
  28. this.level = level;
  29. this.id = id;
  30. this.parendId = parendId;
  31. this.hasChildren = hasChildren;
  32. this.isExpanded = isExpanded;
  33. }
  34. public boolean isExpanded() {
  35. return isExpanded;
  36. }
  37. public void setExpanded(boolean isExpanded) {
  38. this.isExpanded = isExpanded;
  39. }
  40. public String getContentText() {
  41. return contentText;
  42. }
  43. public void setContentText(String contentText) {
  44. this.contentText = contentText;
  45. }
  46. public int getLevel() {
  47. return level;
  48. }
  49. public void setLevel(int level) {
  50. this.level = level;
  51. }
  52. public int getId() {
  53. return id;
  54. }
  55. public void setId(int id) {
  56. this.id = id;
  57. }
  58. public int getParendId() {
  59. return parendId;
  60. }
  61. public void setParendId(int parendId) {
  62. this.parendId = parendId;
  63. }
  64. public boolean isHasChildren() {
  65. return hasChildren;
  66. }
  67. public void setHasChildren(boolean hasChildren) {
  68. this.hasChildren = hasChildren;
  69. }
  70. }

TreeViewAdapter.java:

[java] view plaincopy
  1. package com.example.androidtreeviewdemo.treeview;
  2. import java.util.ArrayList;
  3. import com.example.androidtreeviewdemo.R;
  4. import android.view.LayoutInflater;
  5. import android.view.View;
  6. import android.view.ViewGroup;
  7. import android.widget.BaseAdapter;
  8. import android.widget.ImageView;
  9. import android.widget.TextView;
  10. /**
  11. * TreeViewAdapter
  12. * @author carrey
  13. *
  14. */
  15. public class TreeViewAdapter extends BaseAdapter {
  16. /** 元素数据源 */
  17. private ArrayList<Element> elementsData;
  18. /** 树中元素 */
  19. private ArrayList<Element> elements;
  20. /** LayoutInflater */
  21. private LayoutInflater inflater;
  22. /** item的行首缩进基数 */
  23. private int indentionBase;
  24. public TreeViewAdapter(ArrayList<Element> elements, ArrayList<Element> elementsData, LayoutInflater inflater) {
  25. this.elements = elements;
  26. this.elementsData = elementsData;
  27. this.inflater = inflater;
  28. indentionBase = 50;
  29. }
  30. public ArrayList<Element> getElements() {
  31. return elements;
  32. }
  33. public ArrayList<Element> getElementsData() {
  34. return elementsData;
  35. }
  36. @Override
  37. public int getCount() {
  38. return elements.size();
  39. }
  40. @Override
  41. public Object getItem(int position) {
  42. return elements.get(position);
  43. }
  44. @Override
  45. public long getItemId(int position) {
  46. return position;
  47. }
  48. @Override
  49. public View getView(int position, View convertView, ViewGroup parent) {
  50. ViewHolder holder = null;
  51. if (convertView == null) {
  52. holder = new ViewHolder();
  53. convertView = inflater.inflate(R.layout.treeview_item, null);
  54. holder.disclosureImg = (ImageView) convertView.findViewById(R.id.disclosureImg);
  55. holder.contentText = (TextView) convertView.findViewById(R.id.contentText);
  56. convertView.setTag(holder);
  57. } else {
  58. holder = (ViewHolder) convertView.getTag();
  59. }
  60. Element element = elements.get(position);
  61. int level = element.getLevel();
  62. holder.disclosureImg.setPadding(
  63. indentionBase * (level + 1),
  64. holder.disclosureImg.getPaddingTop(),
  65. holder.disclosureImg.getPaddingRight(),
  66. holder.disclosureImg.getPaddingBottom());
  67. holder.contentText.setText(element.getContentText());
  68. if (element.isHasChildren() && !element.isExpanded()) {
  69. holder.disclosureImg.setImageResource(R.drawable.close);
  70. //这里要主动设置一下icon可见,因为convertView有可能是重用了"设置了不可见"的view,下同。
  71. holder.disclosureImg.setVisibility(View.VISIBLE);
  72. } else if (element.isHasChildren() && element.isExpanded()) {
  73. holder.disclosureImg.setImageResource(R.drawable.open);
  74. holder.disclosureImg.setVisibility(View.VISIBLE);
  75. } else if (!element.isHasChildren()) {
  76. holder.disclosureImg.setImageResource(R.drawable.close);
  77. holder.disclosureImg.setVisibility(View.INVISIBLE);
  78. }
  79. return convertView;
  80. }
  81. /**
  82. * 优化Holder
  83. * @author carrey
  84. *
  85. */
  86. static class ViewHolder{
  87. ImageView disclosureImg;
  88. TextView contentText;
  89. }
  90. }

TreeViewItemClickListener.java:

[java] view plaincopy
  1. package com.example.androidtreeviewdemo.treeview;
  2. import java.util.ArrayList;
  3. import android.view.View;
  4. import android.widget.AdapterView;
  5. import android.widget.AdapterView.OnItemClickListener;
  6. /**
  7. * TreeView item点击事件
  8. * @author carrey
  9. *
  10. */
  11. public class TreeViewItemClickListener implements OnItemClickListener {
  12. /** adapter */
  13. private TreeViewAdapter treeViewAdapter;
  14. public TreeViewItemClickListener(TreeViewAdapter treeViewAdapter) {
  15. this.treeViewAdapter = treeViewAdapter;
  16. }
  17. @Override
  18. public void onItemClick(AdapterView<?> parent, View view, int position,
  19. long id) {
  20. //点击的item代表的元素
  21. Element element = (Element) treeViewAdapter.getItem(position);
  22. //树中的元素
  23. ArrayList<Element> elements = treeViewAdapter.getElements();
  24. //元素的数据源
  25. ArrayList<Element> elementsData = treeViewAdapter.getElementsData();
  26. //点击没有子项的item直接返回
  27. if (!element.isHasChildren()) {
  28. return;
  29. }
  30. if (element.isExpanded()) {
  31. element.setExpanded(false);
  32. //删除节点内部对应子节点数据,包括子节点的子节点...
  33. ArrayList<Element> elementsToDel = new ArrayList<Element>();
  34. for (int i = position + 1; i < elements.size(); i++) {
  35. if (element.getLevel() >= elements.get(i).getLevel())
  36. break;
  37. elementsToDel.add(elements.get(i));
  38. }
  39. elements.removeAll(elementsToDel);
  40. treeViewAdapter.notifyDataSetChanged();
  41. } else {
  42. element.setExpanded(true);
  43. //从数据源中提取子节点数据添加进树,注意这里只是添加了下一级子节点,为了简化逻辑
  44. int i = 1;//注意这里的计数器放在for外面才能保证计数有效
  45. for (Element e : elementsData) {
  46. if (e.getParendId() == element.getId()) {
  47. e.setExpanded(false);
  48. elements.add(position + i, e);
  49. i ++;
  50. }
  51. }
  52. treeViewAdapter.notifyDataSetChanged();
  53. }
  54. }
  55. }

MainActivity.java:

[java] view plaincopy
  1. package com.example.androidtreeviewdemo;
  2. import java.util.ArrayList;
  3. import com.example.androidtreeviewdemo.treeview.Element;
  4. import com.example.androidtreeviewdemo.treeview.TreeViewAdapter;
  5. import com.example.androidtreeviewdemo.treeview.TreeViewItemClickListener;
  6. import android.os.Bundle;
  7. import android.app.Activity;
  8. import android.content.Context;
  9. import android.view.LayoutInflater;
  10. import android.view.Menu;
  11. import android.widget.ListView;
  12. public class MainActivity extends Activity {
  13. /** 树中的元素集合 */
  14. private ArrayList<Element> elements;
  15. /** 数据源元素集合 */
  16. private ArrayList<Element> elementsData;
  17. @Override
  18. protected void onCreate(Bundle savedInstanceState) {
  19. super.onCreate(savedInstanceState);
  20. setContentView(R.layout.activity_main);
  21. LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
  22. init();
  23. ListView treeview = (ListView) findViewById(R.id.treeview);
  24. TreeViewAdapter treeViewAdapter = new TreeViewAdapter(
  25. elements, elementsData, inflater);
  26. TreeViewItemClickListener treeViewItemClickListener = new TreeViewItemClickListener(treeViewAdapter);
  27. treeview.setAdapter(treeViewAdapter);
  28. treeview.setOnItemClickListener(treeViewItemClickListener);
  29. }
  30. private void init() {
  31. elements = new ArrayList<Element>();
  32. elementsData = new ArrayList<Element>();
  33. //添加节点  -- 节点名称,节点level,节点id,父节点id,是否有子节点,是否展开
  34. //添加最外层节点
  35. Element e1 = new Element("山东省", Element.TOP_LEVEL, 0, Element.NO_PARENT, true, false);
  36. //添加第一层节点
  37. Element e2 = new Element("青岛市", Element.TOP_LEVEL + 1, 1, e1.getId(), true, false);
  38. //添加第二层节点
  39. Element e3 = new Element("市南区", Element.TOP_LEVEL + 2, 2, e2.getId(), true, false);
  40. //添加第三层节点
  41. Element e4 = new Element("香港中路", Element.TOP_LEVEL + 3, 3, e3.getId(), false, false);
  42. //添加第一层节点
  43. Element e5 = new Element("烟台市", Element.TOP_LEVEL + 1, 4, e1.getId(), true, false);
  44. //添加第二层节点
  45. Element e6 = new Element("芝罘区", Element.TOP_LEVEL + 2, 5, e5.getId(), true, false);
  46. //添加第三层节点
  47. Element e7 = new Element("凤凰台街道", Element.TOP_LEVEL + 3, 6, e6.getId(), false, false);
  48. //添加第一层节点
  49. Element e8 = new Element("威海市", Element.TOP_LEVEL + 1, 7, e1.getId(), false, false);
  50. //添加最外层节点
  51. Element e9 = new Element("广东省", Element.TOP_LEVEL, 8, Element.NO_PARENT, true, false);
  52. //添加第一层节点
  53. Element e10 = new Element("深圳市", Element.TOP_LEVEL + 1, 9, e9.getId(), true, false);
  54. //添加第二层节点
  55. Element e11 = new Element("南山区", Element.TOP_LEVEL + 2, 10, e10.getId(), true, false);
  56. //添加第三层节点
  57. Element e12 = new Element("深南大道", Element.TOP_LEVEL + 3, 11, e11.getId(), true, false);
  58. //添加第四层节点
  59. Element e13 = new Element("10000号", Element.TOP_LEVEL + 4, 12, e12.getId(), false, false);
  60. //添加初始树元素
  61. elements.add(e1);
  62. elements.add(e9);
  63. //创建数据源
  64. elementsData.add(e1);
  65. elementsData.add(e2);
  66. elementsData.add(e3);
  67. elementsData.add(e4);
  68. elementsData.add(e5);
  69. elementsData.add(e6);
  70. elementsData.add(e7);
  71. elementsData.add(e8);
  72. elementsData.add(e9);
  73. elementsData.add(e10);
  74. elementsData.add(e11);
  75. elementsData.add(e12);
  76. elementsData.add(e13);
  77. }
  78. @Override
  79. public boolean onCreateOptionsMenu(Menu menu) {
  80. // Inflate the menu; this adds items to the action bar if it is present.
  81. getMenuInflater().inflate(R.menu.activity_main, menu);
  82. return true;
  83. }
  84. }

treeview_item.xml:

[html] view plaincopy
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent" >
  5. <ImageView
  6. android:id="@+id/disclosureImg"
  7. android:layout_width="wrap_content"
  8. android:layout_height="wrap_content"
  9. android:layout_centerVertical="true"
  10. android:layout_alignParentLeft="true"/>
  11. <TextView
  12. android:id="@+id/contentText"
  13. android:layout_width="wrap_content"
  14. android:layout_height="wrap_content"
  15. android:layout_centerVertical="true"
  16. android:layout_toRightOf="@id/disclosureImg"/>
  17. </RelativeLayout>

activity_main.xml:

[html] view plaincopy
  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. xmlns:tools="http://schemas.android.com/tools"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. tools:context=".MainActivity" >
  6. <ListView
  7. android:id="@+id/treeview"
  8. android:layout_width="match_parent"
  9. android:layout_height="match_parent"/>
  10. </RelativeLayout>
http://download.csdn.net/detail/carrey1989/6000123

Android UI 之实现多级列表TreeView相关推荐

  1. android 仿qq好友动态,Android UI仿QQ好友列表分组悬浮效果

    本文实例为大家分享了Android UI仿QQ好友列表分组悬浮效果的具体代码,供大家参考,具体内容如下 楼主是在平板上測试的.图片略微有点大,大家看看效果就好 接下来贴源代码: PinnedHeade ...

  2. android二级菜单ui,Android UI 之实现多级树形列表TreeView示例

    所谓TreeView就是在Windows中常见的多级列表树,在Android中系统只默认提供了ListView和ExpandableListView两种列表,最多只支持到二级列表的实现,所以如果想要实 ...

  3. Android UI开发第二篇——多级列表(ExpandableListView)

    开发中很多地方使用到了多级列表,android可以使用ExpandableListView很好的实现,下面模仿了手机qq的实现,见下图. 多级列表使用了ExpandableListView,自定义了A ...

  4. Android UI(五)云通讯录项目之联系人列表,带侧滑选择,带搜索框

    作者:泥沙砖瓦浆木匠 网站:http://blog.csdn.net/jeffli1993 个人签名:打算起手不凡写出鸿篇巨作的人,往往坚持不了完成第一章节. 交流QQ群:[编程之美 36523458 ...

  5. android多级列表

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

  6. Android多级列表的实现

    多级列表是ui入门,没什么特别需要注意的难点,直接上代码: 第一级列表窗口 /*** 第一级列表* 1.编辑状态下选中一个条目,会弹出底部操作栏* 2.非编辑状态下选中条目会跳转到下一级* 3.复选框 ...

  7. Android UI 小结

    UI开发第1篇--自定义列表 编辑器加载中... MainActivity.classpublic class MainActivity extends Activity { @Override pu ...

  8. 安卓listView实现多级列表

    安卓listView实现多级列表 实现两级列表我们可以使用ExpandableListView,但对于实现多级列表,使用ExpandableListView嵌套实现起来就比较费劲,可以使用listVi ...

  9. android教程 - android ui 介绍,多图详解 “Android UI”设计官方教程

    我们曾经给大家一个<MeeGo移动终端设备开发UI设计基础教程>,同时很多朋友都在寻找Android UI开发的教程,我们从Android的官方开发者博客找了一份幻灯片,介绍了一些Andr ...

最新文章

  1. 基于增强现实和脑机接口的机械臂控制系统
  2. 020_html格式化
  3. Project Tango 的一些应用
  4. 使用WordPress的Kyma plugin同Kyma断开连接的实现
  5. 使用springfox 集成swagger 与spring mvc
  6. 带有谓词的Java中的功能样式-第1部分
  7. java hibernate dto_java – 正确使用Entity和DTO在Restful Web服务中...
  8. iptables 指定网卡_LINUX系统下的IPTABLES防火墙系统讲解(二)实战操作
  9. Hibernate学习笔记--映射配置文件详解
  10. hibernate 的三种状态 如何转化的。
  11. Excel VBA简单使用——数据缺失处理
  12. 新手学编程必会的100个代码
  13. Java课程设计-学生成绩管理系统
  14. CSDN账号找回密码的解决方法(原手机号不能使用)
  15. android9.0+wifi叹号,手机wifi连上有个感叹号怎么解决_wifi已连接但有感叹号的处理方法-系统城...
  16. 安全健康的使用计算机就要注意,长时间使用电脑应该注意健康
  17. 2015年最新苹果开发者账号注册流程详解
  18. 浙江省计算机程序比赛员,计算机学子在“图森未来杯”第十七届浙江省大学生程序设计竞赛中斩获金奖...
  19. PPT如何直接转换为word
  20. Maple学习(一)Maple的安装

热门文章

  1. Typora自定义主题分享 (Mac风、图片立体感...)
  2. PHP微信防止token过期,微信调用接口,防止Access_token过期的方法
  3. 没有json数据,自己造!mockjs的使用-模拟数据其实超级简单
  4. 语音邮件 voice mail 概述
  5. asp.net 是什么?
  6. java synchronized_Java中synchronized关键字理解
  7. python基础教程第三版豆瓣-数据结构与算法必读书单吐血整理推荐【附网盘链接】...
  8. 关于桌面程序被安全软件误判为HEUR:Trojan.Win32.Generic的解决方案
  9. Hamilton Jacobi
  10. c语言用分支结构判断最大字符,第3章C语言 分支结构PPT课件.ppt