Heguming

Heguming

0个粉丝

8

问答

0

专栏

6

资料

Heguming  发布于  2015-11-09 17:39:54
采纳率 0%
8个问答
3414

列表树实例

本帖最后由 Heguming 于 2015-11-9 17:48 编辑

    最近,在弄一个电子书App,需要用到列表树结构,相信大家以后也会遇到,特此做下分享,高手请绕行~~~~~~
   
    详细工程请查看附件,下面对其进行简要的分析:

    先介绍下关键类吧:TreeElement,该类是列表树中的每个节点模型,代码如下:

    [code]

    package com.ccl.util.tree;

    import java.util.ArrayList;

    import android.view.View.OnClickListener;

    public class TreeElement {

        private String id;
        private String value;
        private String caption;
        private int position = 0;

        private int level = 0;
        private boolean isHasChild;
        private boolean isExpanded = false;
        private boolean isLastTwig = false;

        private TreeElement parent;
        private ArrayList childList;
        private ArrayList spaceList = new ArrayList();

        private int img_tree_space_n = R.drawable.tree_space_n;
        private int img_tree_space_y = R.drawable.tree_space_y;

        private OnClickListener onClickListener;

        public TreeElement() {
                super();
        }

        public TreeElement(String id, String value, String caption,
                        Boolean isHasChild, OnClickListener onClickListener) {

                this.id = id;
                this.value = value;
                this.caption = caption;

                this.isHasChild = isHasChild;
                if (isHasChild) {
                        this.childList = new ArrayList();
                }
                this.setCaptionOnClickListener(onClickListener);
        }

        public void setId(String id) {
                this.id = id;
        }

        public void setValue(String value) {
                this.value = value;
        }

        public void setCaption(String caption) {
                this.caption = caption;
        }

        public void setPosition(int position) {
                this.position = position;
        }

        public void setLevel(int level) {
                this.level = level;
        }

        public void setIsHasChild(boolean isHasChild) {
                this.isHasChild = isHasChild;
        }

        public void setIsExpanded(boolean isExpanded) {
                this.isExpanded = isExpanded;
        }

        public void setIsLastTwig(boolean isLastTwig) {
                this.isLastTwig = isLastTwig;
        }

        public void setParent(TreeElement parent) {
                this.parent = parent;
        }

        public void setChildList(ArrayList childList) {
                this.childList = childList;
        }

        public void setSpaceList(ArrayList spaceList) {
                this.spaceList = spaceList;
        }

        public void setCaptionOnClickListener(OnClickListener onClickListener) {
                this.onClickListener = onClickListener;
        }

        public String getId() {
                return id;
        }

        public String getValue() {
                return value;
        }

        public String getCaption() {
                return caption;
        }

        public int getPosition() {
                return position;
        }

        public int getLevel() {
                return level;
        }

        public boolean getIsHasChild() {
                return isHasChild;
        }

        public boolean getIsExpanded() {
                return isExpanded;
        }

        public boolean getIsLastTwig() {
                return isLastTwig;
        }

        public TreeElement getParent() {
                return parent;
        }

        public ArrayList getChildList() {
                return childList;
        }

        public ArrayList getSpaceList() {
                return spaceList;
        }

        public OnClickListener getOnClickListener() {
                return onClickListener;
        }

        public void addChild(TreeElement treeElement) {

                TreeElement parent = this;
                treeElement.parent = parent;
                if (parent != null && childList != null && childList.size() > 0) {
                        TreeElement child = childList.get(childList.size() - 1);
                        child.setIsLastTwig(false);
                        childList.set(childList.size() - 1, child);
                }

                childList.add(treeElement);
                parent.setIsHasChild(true);
                parent.setChildList(childList);

                treeElement.setLevel(this.level + 1);
                treeElement.setIsLastTwig(true);

                if (this.level > 0) {
                        treeElement.getSpaceList().addAll(spaceList);
                        if (isLastTwig) {
                                treeElement.getSpaceList().add(img_tree_space_n);
                        } else {
                                treeElement.getSpaceList().add(img_tree_space_y);
                        }
                }
        }
}   

    [/code]

    该类主要包含了以下几个参数:

    构造参数:

    id---节点序列号,采用String类型,可以清楚地知道其所属关系,即该节点位于该列表树的第几层。

    value--节点值,即该节点所包含的数据。

    caption---节点标题,显示在屏幕中的节点标题信息。

    isHasChild---该节点是否包含子节点。

    onClickListener---事件监听器,通过该事件监听器,可以设置每次点击事件所需要的响应。

    其他参数:

    position---该节点在列表中的位置,包括展开树后的子节点在内。

    level---该节点在树的第几层。

    parent---该节点的父节点,同为TreeElement类型。

    childList---该节点的子节点的集合。

    spaceList---所有父节点连线图形的集合,如下图:

   

   

    isExpanded---该节点是否处于展开状态,可根据此值,分别设置节点的图形标志,如下图:

   

   

   

    isLastTwig---该节点是否为本层的最后一个节点,可根据此值,分别设置节点的连接标志,如下图:

   

   

    连线图形、图形标志及连接标志在视图中的位置:

   
   
    其中,属于该节点本身的固有的参数为:id、value、caption及onClickListener,这四个参数加上isHasChild,可直接在初始化列表树时直接赋值。

    其余参数,包括isHasChild,isExpanded,isLastTwig,position,level,parent,childList,spaceList在内,属于该节点在该树中的关系属性,不可直接通过实例化该类赋值,需要在以下方法中分别赋值:

    level、parent、childList、spaceList、isLastTwig---这些变量通过执行addChild(TreeElement treeElement)方法时赋值。

    [code]
    public void addChild(TreeElement treeElement) {

                TreeElement parent = this;
                treeElement.parent = parent;
                if (parent != null && childList != null && childList.size() > 0) {
                        TreeElement child = childList.get(childList.size() - 1);
                        child.setIsLastTwig(false);
                        childList.set(childList.size() - 1, child);
                }

                childList.add(treeElement);
                parent.setIsHasChild(true);
                parent.setChildList(childList);

                treeElement.setLevel(this.level + 1);
                treeElement.setIsLastTwig(true);

                if (this.level > 0) {
                        treeElement.getSpaceList().addAll(spaceList);
                        if (isLastTwig) {
                                treeElement.getSpaceList().add(img_tree_space_n);
                        } else {
                                treeElement.getSpaceList().add(img_tree_space_y);
                        }
                }
        }
    [/code]

    由该方法可以看出,当对某一个节点添加子节点时,首先将该子节点的父节点设置为当前节点parent,即对需要添加的子节点parent参数赋值。

    然后,将当前父节点的最后一个子节点的IsLastTwig属性设置为false,将该子节点的IsLastTwig属性设置为true,即对isLastTwig参数赋值。

    同时,将需要添加的子节点添加至当前父节点ChildList中,即对childList参数赋值,并再此将该父节点IsHasChild属性设置为true,即当前节点包含子节点。

    最后,将需要添加的子节点的层级设置为当前父节点的层级+1(level + 1),即对level参数赋值,并根据level层级,将所有父节点的连线图形,并加上自身的连线图形,全部添加至spaceList,即对spaceList参数赋值。

    isExpanded、position---当响应含有子节点的当前节点的点击事件时,这两个变量被赋值。通过对isExpanded变量进行赋值,进而改变父节点的展开/收缩状态(isExpanded为true时展开)。通过对position变量进行赋值,进而设置该节点在列表树中的位置。当isExpanded为false时,position的值为该节点在当前层级(level)中的位置。相反,当isExpanded的值为true时,position的值还需加上其子节点后,在所有层级(level)中的位置。对这两个变量赋值的方法在TreeViewAdapter中,代码如下:

    [code]
   
    package com.ccl.util.tree;

    import java.util.ArrayList;

    import android.content.Context;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.view.ViewGroup;
    import android.widget.ArrayAdapter;
    import android.widget.ImageView;
    import android.widget.LinearLayout;
    import android.widget.TextView;
    import android.widget.Toast;

    public class TreeViewAdapter extends ArrayAdapter {
        private int img_leaf = R.drawable.icon_user;// 没有子节点的节点图标
        private int img_expand = R.drawable.outline_list_expand;// 展开的图标
        private int img_collapse = R.drawable.outline_list_collapse;// 收缩的图标
        private int img_tree_space_1 = R.drawable.tree_space_1;// 连线图形
        private int img_tree_space_2 = R.drawable.tree_space_2;

        private Context context;
        private ArrayList treeElementList;
        private int viewResourceId;

        public TreeViewAdapter(Context context, int viewResourceId,
                        ArrayList treeElementList) {
                super(context, viewResourceId, treeElementList);
                this.context = context;
                this.viewResourceId = viewResourceId;
                this.treeElementList = treeElementList;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
                ViewHolder holder;

                convertView = LayoutInflater.from(context)
                                .inflate(viewResourceId, null);
                holder = new ViewHolder();
                holder.caption = (TextView) convertView.findViewById(R.id.caption);
                holder.icon = (ImageView) convertView.findViewById(R.id.icon);
                holder.space = (LinearLayout) convertView.findViewById(R.id.space);
                convertView.setTag(holder);

                TreeElement treeElement = treeElementList.get(position);

                int level = treeElement.getLevel();
                if (level == 0) {// 根节点

                } else {
                        ArrayList spaceList = treeElement.getSpaceList();

                        // 绘制前面的组织架构线条
                        for (int i = 0; i < spaceList.size(); i++) {
                                ImageView img = new ImageView(context);
                                img.setImageResource(spaceList.get(i));
                                holder.space.addView(img);
                        }

                        ImageView img = new ImageView(context);
                        // 节点图标
                        if (treeElement.getIsLastTwig()) {
                                img.setImageResource(img_tree_space_2);
                        } else {
                                img.setImageResource(img_tree_space_1);
                        }

                        holder.space.addView(img);
                }
                if (treeElement.getIsHasChild()) {
                        if (treeElement.getIsExpanded()) {
                                holder.icon.setImageResource(img_expand);
                        } else {
                                holder.icon.setImageResource(img_collapse);
                        }
                        holder.icon.setOnClickListener(new TreeElementIconClickListener(
                                        context, treeElementList, this, treeElement.getPosition()));
                } else {
                        holder.icon.setImageResource(img_leaf);
                }

                holder.caption.setText(treeElement.getCaption()); // 设置标题
                if (treeElement.getOnClickListener() != null) { // 设置文字的点击事件
                        holder.caption.setTag(treeElement.getValue());
                        holder.caption.setOnClickListener(treeElement.getOnClickListener());

                }
                return convertView;
        }

        class ViewHolder {
                LinearLayout space;
                TextView caption;
                ImageView icon;
        }

        public static class TreeElementIconClickListener implements OnClickListener {
                private Context context;
                private ArrayList treeElementList;
                private TreeViewAdapter treeViewAdapter;
                private int position;

                public TreeElementIconClickListener(Context mContext,
                                ArrayList treeElementList,
                                TreeViewAdapter treeViewAdapter, int position) {
                        this.context = mContext;
                        this.treeElementList = treeElementList;
                        this.treeViewAdapter = treeViewAdapter;
                        this.position = position;
                }

                @Override
                public void onClick(View v) {

                        if (!treeElementList.get(position).getIsHasChild()) {
                                Toast.makeText(context,
                                                treeElementList.get(position).getCaption(),
                                                Toast.LENGTH_SHORT).show();
                                return;
                        }

                        if (treeElementList.get(position).getIsExpanded()) {
                                treeElementList.get(position).setIsExpanded(false);
                                TreeElement treeElement = treeElementList.get(position);
                                ArrayList tempList = new ArrayList();

                                for (int i = position + 1; i < treeElementList.size(); i++) {
                                        if (treeElement.getLevel() >= treeElementList.get(i)
                                                        .getLevel()) {
                                                break;
                                        }
                                        tempList.add(treeElementList.get(i));
                                }

                                treeElementList.removeAll(tempList);
                                for (int i = position + 1; i < treeElementList.size(); i++) {

                                        treeElementList.get(i).setPosition(i);
                                }
                                treeViewAdapter.notifyDataSetChanged();
                        } else {
                                TreeElement treeElement = treeElementList.get(position);
                                treeElement.setIsExpanded(true);
                                int level = treeElement.getLevel();

                                ArrayList tempList = treeElement.getChildList();

                                for (int i = 0; i < tempList.size(); i++) {
                                        TreeElement element = tempList.get(i);
                                        element.setLevel(level + 1);
                                        element.setIsExpanded(false);
                                        treeElementList.add(position + i + 1, element);
                                }
                                for (int i = position + 1; i < treeElementList.size(); i++) {

                                        treeElementList.get(i).setPosition(i);
                                }
                                treeViewAdapter.notifyDataSetChanged();
                        }
                }
        }
}

    [/code]

    在getView(int position, View convertView, ViewGroup parent)方法中,先获取当前节点treeElement,然后根据treeElement层级level是否为0(即是否为根节点)进行分别处理。

    当level不为0时,获取spaceList所有父节点的连线图形,通过addView(View view)方法,将所有连线图形添加至列表item相应View中。  

    同时,通过获取节点treeElement的IsLastTwig属性,判断当前节点是否为相同层级下的最后一个节点,并根据此判断,分别向列表item相应View中添加不同的连接标志。

    相反,当level等于0时,即当前节点为根节点时,以上图形无须添加。

    接着,判断当前节点有无子节点。如果含有,则获取节点IsExpanded属性,并根据该属性的值,设置不同的图形标志。同时,为当前节点的图形标志设置onClick监听器。

    如果不含有,则直接将当前节点的图形标志设为终节点即可(即不包含子节点的节点)。

    最后,为当前节点设置标题caption及值value,标题通过setText()方法显示在TextView上,值则通过setTag()方法存储在TextView中。

    另外地,需要特意说明一下图形标志的点击事件,即TreeElementIconClickListener类。

    该类主要实现了onClick(View view)方法,在该方法内部,主要做了以下几件事:

    1.判断当前点击节点的展开/收缩状态。

    2.若该节点为展开状态,响应点击事件后,设置该节点为收缩状态:treeElementList.get(position).setIsExpanded(false)。然后将该节点内的所有子节点添加至新的TreeElement集合tempList中,通过该集合对treeElementList进行定向删除:treeElementList.removeAll(tempList)。最后,更新列表position及整个列表:treeViewAdapter.notifyDataSetChanged()。

    3.若该节点为收缩状态,响应点击事件后,设置该节点为展开状态:treeElement.setIsExpanded(true),然后通过treeElement获取当前层级level及当前节点的子节点集合:tempList,并将该集合添加至treeElementList中,同时设置子节点的相关属性:element.setLevel(level + 1)、element.setIsExpand(false)。最后,更新列表position及整列表:
treeViewAdapter.notifyDataSetChanged()。

    最后,是MainActivity代码,主要功能是初始化树,向其中添加节点,并更新列表。

    [code]

    package com.ccl.util.tree;

    import java.util.ArrayList;

    import android.app.Activity;
    import android.os.Bundle;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.ListView;
    import android.widget.Toast;

    public class MainActivity extends Activity {
        private ListView lv_tree;
        private TreeViewAdapter treeViewAdapter;
        private ArrayList rootList;

        @Override
        protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
                lv_tree = (ListView) findViewById(R.id.lv_tree);
                rootList = new ArrayList();
                treeViewAdapter = new TreeViewAdapter(this, R.layout.atom_tree,
                                rootList);
                lv_tree.setAdapter(treeViewAdapter);

                OnClickListener onClickListener = new OnClickListener() {
                        @Override
                        public void onClick(View v) {
                                Toast.makeText(MainActivity.this, "value:" + v.getTag(),
                                                Toast.LENGTH_LONG).show();
                        }
                };

                initTree(onClickListener);
                treeViewAdapter.notifyDataSetChanged();

                // TreeElementIconClickListener treeElementIconClickListener = new
                // TreeElementIconClickListener(
                // MainActivity.this, mRootList, treeViewAdapter, 0);
                // treeElementIconClickListener.onClick(null);
        }

        private void initTree(OnClickListener onClickListener) {
                // TODO Auto-generated method stub

                TreeElement rootElement = new TreeElement("0", "根结点", "根节点", true,
                                onClickListener);

                TreeElement treeElement1 = new TreeElement("1", "节点1", "节点1", true,
                                onClickListener);
                TreeElement treeElement2 = new TreeElement("2", "节点2", "节点2", false,
                                onClickListener);
                TreeElement treeElement3 = new TreeElement("3", "节点3", "节点3", false,
                                onClickListener);
                TreeElement treeElement4 = new TreeElement("4", "节点4", "节点4", true,
                                onClickListener);

                rootElement.addChild(treeElement1);
                rootElement.addChild(treeElement2);
                rootElement.addChild(treeElement3);
                rootElement.addChild(treeElement4);

                TreeElement treeElement1_1 = new TreeElement("1_1", "节点1_1", "节点1_1",
                                true, onClickListener);
                TreeElement treeElement1_2 = new TreeElement("1_2", "节点1_2", "节点1_2",
                                false, onClickListener);
                TreeElement treeElement1_3 = new TreeElement("1_3", "节点1_3", "节点1_3",
                                true, onClickListener);

                treeElement1.addChild(treeElement1_1);
                treeElement1.addChild(treeElement1_2);
                treeElement1.addChild(treeElement1_3);

                TreeElement treeElement4_1 = new TreeElement("4_1", "节点4_1", "节点4_1",
                                true, onClickListener);
                TreeElement treeElement4_2 = new TreeElement("4_2", "节点4_2", "节点4_2",
                                false, onClickListener);
                TreeElement treeElement4_3 = new TreeElement("4_3", "节点4_3", "节点4_3",
                                true, onClickListener);

                treeElement4.addChild(treeElement4_1);
                treeElement4.addChild(treeElement4_2);
                treeElement4.addChild(treeElement4_3);

                TreeElement treeElement1_1_1 = new TreeElement("1_1_1", "节点1_1_1",
                                "节点1_1_1", false, onClickListener);

                treeElement1_1.addChild(treeElement1_1_1);

                TreeElement treeElement1_3_1 = new TreeElement("1_3_1", "节点1_3_1",
                                "节点1_3_1", true, onClickListener);
                TreeElement treeElement1_3_2 = new TreeElement("1_3_2", "节点1_3_2",
                                "节点1_3_2", false, onClickListener);

                treeElement1_3.addChild(treeElement1_3_1);
                treeElement1_3.addChild(treeElement1_3_2);

                TreeElement treeElement4_1_1 = new TreeElement("4_1_1", "节点4_1_1",
                                "节点4_1_1", false, onClickListener);
                TreeElement treeElement4_3_1 = new TreeElement("4_3_1", "节点4_3_1",
                                "节点4_3_1", false, onClickListener);

                treeElement4_1.addChild(treeElement4_1_1);
                treeElement4_3.addChild(treeElement4_3_1);

                TreeElement treeElement1_3_1_1 = new TreeElement("1_3_1_1",
                                "节点1_3_1_1", "节点1_3_1_1", false, onClickListener);

                treeElement1_3_1.addChild(treeElement1_3_1_1);

                rootList.add(rootElement);
        }
}

    [/code]

    其中,注释部分代码的功能为展开根节点,用户可根据需要自行添加。

    好了,以上代码分析完毕,谢谢!

    原创,转载请注明出处 :)

    附件:tree.rar
易百纳技术社区文件: tree.rar
下载
我来回答
回答2个
时间排序
认可量排序

jp1017

0个粉丝

78

问答

0

专栏

9

资料

jp1017 2015-11-13 19:53:17
认可0
下来看看什么玩意,可以提交到github

kgui

0个粉丝

13

问答

0

专栏

4

资料

kgui 2015-11-14 13:29:57
认可0
赞,感谢分享
或将文件直接拖到这里
悬赏:
E币
网盘
* 网盘链接:
* 提取码:
悬赏:
E币

Markdown 语法

  • 加粗**内容**
  • 斜体*内容*
  • 删除线~~内容~~
  • 引用> 引用内容
  • 代码`代码`
  • 代码块```编程语言↵代码```
  • 链接[链接标题](url)
  • 无序列表- 内容
  • 有序列表1. 内容
  • 缩进内容
  • 图片![alt](url)
+ 添加网盘链接/附件

Markdown 语法

  • 加粗**内容**
  • 斜体*内容*
  • 删除线~~内容~~
  • 引用> 引用内容
  • 代码`代码`
  • 代码块```编程语言↵代码```
  • 链接[链接标题](url)
  • 无序列表- 内容
  • 有序列表1. 内容
  • 缩进内容
  • 图片![alt](url)
相关问答
无更多相似问答 去提问
举报反馈

举报类型

  • 内容涉黄/赌/毒
  • 内容侵权/抄袭
  • 政治相关
  • 涉嫌广告
  • 侮辱谩骂
  • 其他

详细说明

易百纳技术社区