43

I know there is the ExpandableListView but it only supports up to 2 levels. I need a true treeview vertical list with at least up to ~5 levels (more is better).

Any suggestions?

edit:

I see talk about using a Custom Adapter and setting the padding based on the items level.

I have an unsorted ArrayList of objects that have an ID and parent ID, and I dynamically add items to this array as well.

Can anyone give me some examples of how I can go about doing this?

abatishchev
  • 92,232
  • 78
  • 284
  • 421
Daniel Sloof
  • 12,051
  • 14
  • 68
  • 104
  • See is the link for My project where N-level Tree list view can be achieved.https://github.com/Jaldips/Android-MultilevelTreeListView – Jaldip Katre Jan 06 '14 at 08:38

10 Answers10

20

I had the same issue. You can check out my implementation AndroidTreeView.

  • Its N-level tree.

  • Custom style for nodes

  • Save state after rotation

AndroidTreeView

bmelnychuk
  • 1,090
  • 8
  • 14
  • Thanks it's helpful, Can I add a level with horizontal icons, – Anup Mar 25 '17 at 08:37
  • 1
    Can you dynamically modify the view? Specifically, if I initially create a tree that contains an endpoint (leaf) node, can I later change that to a folder? – FractalBob Apr 17 '17 at 18:06
15

Our company also open-sourced a solution for this. It is available as library, so very easy to use: http://code.google.com/p/tree-view-list-android/

enter image description here

Jarek Potiuk
  • 12,572
  • 2
  • 50
  • 49
11

i solved it for me, posting in a similar thread: other thread

enter image description here

Community
  • 1
  • 1
2red13
  • 10,616
  • 7
  • 37
  • 52
7

Answering my own question, since we implemented this many months ago.

Our implementation in an open-source proejct.

yakhtarali
  • 342
  • 11
  • 25
Daniel Sloof
  • 12,051
  • 14
  • 68
  • 104
  • your link is not working . can you please update it? or can you paste some sudo code here.. – Jeegar Patel Apr 16 '12 at 10:47
  • @Mr.32 - there are some DNS issues, site will be up soon. In the meanwhile you can check a mirror on github: https://github.com/haxar/mangler/blob/master/android/src/org/mangler/android/ChannelList.java – Daniel Sloof Apr 16 '12 at 11:04
  • updated link: https://github.com/pi0/mangler/blob/master/android/src/org/mangler/android/ChannelList.java – Ich Jan 04 '16 at 21:49
4

I have found an easier solution to this problem, as I myself am somewhat intermediate in my coding skills. In my situation, I needed a Windows-themed Tree View, which after brainstorming ideas, I was able to implement with hardly any coding!

Here's the trick: use a WebView and an embedded HTML page to display a custom Tree View, and use Android's super handy JavaScript communication interface to receive selections & clicks: Proof of Concept Example on Android-er Blog

With this power we can take advantage of a large collection of JS/CSS control snippets around the web. Themeable Windows7-Style jQuery TreeView control -- jsTree

Lot's of possibilities and power with Android out there, happy coding!

Aaron Gillion
  • 2,071
  • 3
  • 17
  • 29
  • 3
    The most resource eating solution for the problem. But i fear thats the future of our industry. – Lothar Jan 02 '19 at 20:17
3

I think if multilevel expandablelist is done properly it actually works and looks great. Here is another example of http://code.google.com/p/tree-view-list-android/

enter image description here

dotsa
  • 833
  • 1
  • 10
  • 15
  • Hi dotsa ! I am trying to implement this treeview from google code. Since you already implemented it, can you help me with some issues regarding this? If OK, please give me a knock at fahim.ahmed1988@gmail.com . Thanks ! – Fahim Ahmed Mar 13 '13 at 11:17
3

I found the link below very, very useful. It describes alternative ways of storing tree structures in two dimensional data structures (typically a database table).

I think you'll find the paradigm easy to understand and implement.

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

As of how to visualize this in Android is another question. I would perhaps write my own widget from scratch if the "padded" list items solution isn't sufficient.

dbm
  • 9,888
  • 6
  • 41
  • 55
  • Thank you so very much for revising the link @Jarrod Dixon! Ever since Oracle removed the (originally) freely available knowledge resource (originating from MySQL developers, MySQL was later bought by Sun who in turn - unfortunately if you ask me - was bought by Oracle) I've spent a respectable amount of time to find an alternative resource for it (obviously not "respectable amount of time" enough, though). Thanks again! – dbm Jun 07 '12 at 09:23
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;
    }
}

}

abatishchev
  • 92,232
  • 78
  • 284
  • 421
Arun
  • 123
  • 1
  • 1
  • 5
2

I agree with pjv, at least for phone-size devices. It would be better to organize the widget to show one group of siblings at a time in a ListView. This could be done in a single activity that keeps track of its position in the tree. It could show a header with breadcrumbs showing the path to the parent of the items currently on display.

A multi-level tree view may be appropriate for a tablet device, but a phone does not have enough real estate to support the proposed 5 levels (with everything having to be big enough for fingers).

Nevertheless, if you are set on a tree view, don't look at subclassing ExpandableListView. It operates internally by packing the parent and child indices (each an int) into a single long. This internal representation makes it virtually impossible to extend beyond 2 levels.

Ted Hopp
  • 222,293
  • 47
  • 371
  • 489
1

I'd start by making the data structure more representative of what it's meant to contain. Since you have an array of items and each child can have it's own array of items, each with its own array, etc. I'd consider using a class with two members: an object that represents the data for this particular item and an array that holds the item's children. Each child would itself be an instance of the class so that it, too, could have children.

private class ParentAndKids { Object parent; Array kids; }

Your adapter would then have an array of ParentAndKids objects which represents the top layer. You'd add and remove list items based on which parents were expanded.

Ginger McMurray
  • 1,184
  • 2
  • 19
  • 36