安卓树形视图

42

我知道有ExpandableListView,但它只支持2级。我需要一个真正的树形结构垂直列表,至少支持5级(支持更多更好)。

有什么建议吗?

编辑:

我看到有人谈论使用自定义适配器,并根据项目级别设置填充。

我有一个未排序的对象ArrayList,其中包含ID和父ID,并且我也会动态添加项目到此数组中。

有人可以给我一些关于如何做到这一点的示例吗?


以下是我的项目链接,可以实现N级树形列表视图。https://github.com/Jaldips/Android-MultilevelTreeListView - Jaldip Katre
11个回答

21

我遇到了同样的问题。您可以查看我的实现 AndroidTreeView


  • 它是N级树。

  • 节点有自定义样式。

  • 旋转后保存状态。

AndroidTreeView


谢谢,这很有帮助。我可以添加一个水平图标的级别吗? - Anup
1
你能动态修改视图吗?具体来说,如果我最初创建一个包含端点(叶子)节点的树形结构,我后来能将其更改为文件夹吗? - FractalBob

15

1
你的开源项目中没有下载链接。 - Sandip Jadhav

10

我在一个类似的帖子中解决了这个问题:

其他帖子

输入图像描述


7

你的链接无法使用。请问能否更新一下呢?或者您可以在这里粘贴一些伪代码吗? - Jeegar Patel
@Mr.32 - 目前存在一些 DNS 问题,网站很快就会恢复。在此期间,您可以在 GitHub 上检查镜像:https://github.com/haxar/mangler/blob/master/android/src/org/mangler/android/ChannelList.java - Daniel Sloof
更新的链接:https://github.com/pi0/mangler/blob/master/android/src/org/mangler/android/ChannelList.java - Ich

4
我已经找到了一个更简单的解决方案,因为我自己的编码技能有点中级水平。在我的情况下,我需要一个Windows主题的树形视图,在头脑风暴之后,我可以用很少的编码实现它!这是诀窍:使用WebView和嵌入的HTML页面来显示自定义Tree View,并使用Android非常方便的JavaScript通信接口来接收选择和点击:Android-er Blog 中的概念验证示例。 有了这个功能,我们可以利用网络上大量的JS/CSS控件片段。 可主题化的 Windows7 风格 jQuery TreeView 控件 - jsTree 。 在 Android 上会有许多可能性和强大的功能,祝愉快编码!

3
问题最耗资源的解决方案。但我担心这将成为我们行业的未来。 - Lothar

3

我发现下面的链接非常有用,它描述了将树结构存储在二维数据结构中(通常是数据库表)的替代方法。

我认为您会发现这种范例易于理解和实现。

http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/

如何在Android中可视化这个问题,则另说。如果"填充"列表项的解决方案不足够,我可能会从头开始编写自己的小部件。


非常感谢您修正链接,@Jarrod Dixon!自从Oracle删除了(最初)免费提供的知识资源(源自MySQL开发人员,MySQL后来被Sun收购,而Sun又被Oracle收购-如果您问我,这是不幸的),我花费了相当多的时间寻找替代资源(显然不够“相当多的时间”)。再次感谢! - dbm

3

嗨dotsa!我正在尝试从Google代码实现这个treeview。既然你已经实现了它,你能帮我解决一些关于它的问题吗?如果可以的话,请发邮件给我:fahim.ahmed1988@gmail.com。谢谢! - Fahim Ahmed

2
package com.expand.search;

import android.app.ExpandableListActivity;
import android.os.Bundle;
import android.view.ContextMenu;
import android.view.Gravity;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.ContextMenu.ContextMenuInfo;
import android.widget.AbsListView;
import android.widget.BaseExpandableListAdapter;
import android.widget.ExpandableListAdapter;
import android.widget.ExpandableListView;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ExpandableListView.ExpandableListContextMenuInfo;

   /** Demonstrates expandable lists using a custom {@link ExpandableListAdapter}
    * from {@link BaseExpandableListAdapter}.
   */
public class expands extends ExpandableListActivity {

ExpandableListAdapter mAdapter;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Set up our adapter
    mAdapter = new MyExpandableListAdapter();
    setListAdapter(mAdapter);
    registerForContextMenu(getExpandableListView());
}

@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
    menu.setHeaderTitle("Sample menu");
    menu.add(0, 0, 0, R.string.expandable_list_sample_action);
}

@Override
public boolean onContextItemSelected(MenuItem item) {
    ExpandableListContextMenuInfo info = (ExpandableListContextMenuInfo) item.getMenuInfo();

    String title = ((TextView) info.targetView).getText().toString();

    int type = ExpandableListView.getPackedPositionType(info.packedPosition);
    if (type == ExpandableListView.PACKED_POSITION_TYPE_CHILD) {
        int groupPos = ExpandableListView.getPackedPositionGroup(info.packedPosition); 
        int childPos = ExpandableListView.getPackedPositionChild(info.packedPosition); 
        Toast.makeText(this, title + ": Child " + childPos + " clicked in group " + groupPos,   
                Toast.LENGTH_SHORT).show();
        return true;
    } else if (type == ExpandableListView.PACKED_POSITION_TYPE_GROUP) {
        int groupPos = ExpandableListView.getPackedPositionGroup(info.packedPosition); 
        Toast.makeText(this, title + ": Group " + groupPos + " clicked", Toast.LENGTH_SHORT).show();
        return true;
    }

    return false;
}

/** A simple adapter which maintains an ArrayList of photo resource Ids. 
 * Each photo is displayed as an image. This adapter supports clearing the
 * list of photos and adding a new photo.
 */
public class MyExpandableListAdapter extends BaseExpandableListAdapter {
    // Sample data set.  children[i] contains the children (String[]) for groups[i].
    private String[] groups = { "Category1", "Category2", "Category3", "Category4" };
    private String[][] children = {
            { "Charity1", "Charity2", "Charity3", "Charity4" },
            { "Charity5", "Charity6", "Charity7", "Charity8" },
            { "Charity9", "Charity10" },
            { "Charity11", "Charity12" }
    };

    public Object getChild(int groupPosition, int childPosition) {
        return children[groupPosition][childPosition];
    }

    public long getChildId(int groupPosition, int childPosition) {
        return childPosition;
    }

    public int getChildrenCount(int groupPosition) {
        return children[groupPosition].length;
    }

    public TextView getGenericView() {
        // Layout parameters for the ExpandableListView
        AbsListView.LayoutParams lp = new AbsListView.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT, 64);

        TextView textView = new TextView(expands.this);
        textView.setLayoutParams(lp);
        // Center the text vertically
        textView.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT);
        // Set the text starting position
        textView.setPadding(36, 0, 0, 0);
        return textView;
    }

    public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
            View convertView, ViewGroup parent) {
        TextView textView = getGenericView();
        textView.setText(getChild(groupPosition, childPosition).toString());
        return textView;
    }

    public Object getGroup(int groupPosition) {
        return groups[groupPosition];
    }

    public int getGroupCount() {
        return groups.length;
    }

    public long getGroupId(int groupPosition) {
        return groupPosition;
    }

    public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
            ViewGroup parent) {
        TextView textView = getGenericView();
        textView.setText(getGroup(groupPosition).toString());
        return textView;
    }

    public boolean isChildSelectable(int groupPosition, int childPosition) {
        return true;
    }

    public boolean hasStableIds() {
        return true;
    }
}

}


2
我们可以进行超过两层的嵌套吗? - Jeegar Patel

2

我同意pjv的观点,至少对于手机尺寸的设备来说是这样。最好的方法是在ListView中组织小部件,一次只显示一个兄弟姐妹组。这可以在单个活动中完成,该活动跟踪其在树中的位置。它可以显示面包屑导航的标题,显示当前显示项目的父项路径。

多级树视图可能适用于平板电脑,但手机没有足够的空间来支持所提议的5个级别(每个级别都必须足够大,以适应手指)。

尽管如此,如果您坚持要使用树形视图,请不要考虑子类化ExpandableListView。它通过将父项和子项索引(每个int)打包到单个长整型中来进行内部操作。这种内部表示使得扩展超过2个级别几乎不可能。


1
我会从让数据结构更符合其所包含内容的角度入手。由于您有一个项目数组,每个子项都可以有自己的项目数组,每个数组又可以有自己的数组等等。我建议使用一个类来表示这个数据结构,该类有两个成员:一个表示此特定项目数据的对象和一个保存该项目子项的数组。每个子项本身也是该类的实例,以便它也可以有子项。
私有类ParentAndKids { 对象父级; 数组子项; }
然后,您的适配器将具有ParentAndKids对象的数组,该数组表示顶层。您将根据展开哪些父项来添加和删除列表项。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接