Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android Treeview

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?

like image 603
Daniel Sloof Avatar asked Jul 17 '10 14:07

Daniel Sloof


People also ask

What is TreeView used for?

The TreeView control is used to display hierarchical representations of items similar to the ways the files and folders are displayed in the left pane of the Windows Explorer. Each node may contain one or more child nodes.

What is view tree in Android?

android.view.ViewTreeObserver. A view tree observer is used to register listeners that can be notified of global changes in the view tree. Such global events include, but are not limited to, layout of the whole tree, beginning of the drawing pass, touch mode change....

What is TreeView control?

A tree-view control is a window that displays a hierarchical list of items, such as the headings in a document, the entries in an index, or the files and directories on a disk. Each item consists of a label and an optional bitmapped image, and each item can have a list of subitems associated with it.


10 Answers

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

like image 93
bmelnychuk Avatar answered Oct 03 '22 07:10

bmelnychuk


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

like image 44
Jarek Potiuk Avatar answered Oct 03 '22 07:10

Jarek Potiuk


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

enter image description here

like image 42
2red13 Avatar answered Oct 03 '22 07:10

2red13


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

Our implementation in an open-source proejct.

like image 45
Daniel Sloof Avatar answered Oct 03 '22 07:10

Daniel Sloof


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!

like image 33
Aaron Gillion Avatar answered Oct 03 '22 05:10

Aaron Gillion


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.

like image 33
dbm Avatar answered Oct 03 '22 07:10

dbm


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

like image 43
dotsa Avatar answered Oct 03 '22 05:10

dotsa


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.

like image 30
Ted Hopp Avatar answered Oct 03 '22 07:10

Ted Hopp


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;
    }
}

}

like image 23
Arun Avatar answered Oct 03 '22 06:10

Arun


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.

like image 28
Ginger McMurray Avatar answered Oct 03 '22 05:10

Ginger McMurray