Android中的多级TreeView

时间:2013-10-24 07:13:41

标签: android treeview

有人可以告诉如何在Android中实现级别超过2的Treeview吗? 我想用textview和复选框创建一个多级树视图。

2 个答案:

答案 0 :(得分:2)

您可以查看我的实施AndroidTreeView

this thread也很有用

答案 1 :(得分:1)

您必须扩展两个类才能创建树视图。这是示例代码

package com.example.mytreeview;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ExpandableListView;
import android.widget.SimpleExpandableListAdapter;

public class CustomExpandableListAdapter extends SimpleExpandableListAdapter {

Context context = null;
ExpandableListView topList;
LayoutInflater inflater = null;
HashMap<Integer, ArrayList<String[]>> data;
ArrayList<Map<String, String>> groupData;
ArrayList<List<Map<String, String>>> childData;
List<Map<String, String>> children;
Map<String, String> childMap;
ArrayList<String[]> list;
int listSize;
HashMap<Integer, CustomExpandableListView> elvCache = new HashMap<Integer, CustomExpandableListView>();

public CustomExpandableListAdapter( Context context, 
        ExpandableListView topList, 
        HashMap<Integer, ArrayList<String[]>> data, 
        ArrayList<Map<String, String>> groupData, 
        ArrayList<List<Map<String, String>>> childData ) {      
    super(
            context,
            groupData,
            R.layout.grouprow,
            new String[] { "name", "_id", "parentId" },
            new int[] { R.id.tvLevelName, R.id.tvId, R.id.tvParentId },
            childData,
            R.layout.childrow,
            new String[] { "name", "_id", "parentId" },
            new int[] { R.id.tvLevelName, R.id.tvId, R.id.tvParentId }
    );  

    this.context = context;
    this.topList = topList;
    this.data = data;
    inflater = LayoutInflater.from(context);
}   

@Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {       

    // if there are no child nodes then simply show the single row  
    HashMap <String, String> levelinfo = (HashMap<String, String>)getChild(groupPosition, childPosition); 
    Integer levelId = Integer.valueOf(levelinfo.get("_id"));

    if (levelinfo.get("hasChild").toString().equalsIgnoreCase("N")) {
        View v = super.getChildView(groupPosition, childPosition, isLastChild, convertView, parent);            
        return v;   
    }
    else
    { // if the node contains child nodes then insert new expandable list           
        CustomExpandableListView v = null;

        v = elvCache.get(levelId);
        if (v == null) {
            CreateData(levelinfo);
            v = new CustomExpandableListView(context, null, android.R.attr.expandableListViewStyle);
            v.setRows(groupData.size());        
            v.setPadding(10, 0, 0, 0);
            v.setAdapter(new CustomExpandableListAdapter(context, topList, data, groupData, childData));
            v.setOnGroupClickListener(new Level2GroupExpandListener());
            elvCache.put(levelId, v);               
        }
        return super.getChildView(groupPosition, childPosition, isLastChild, v, parent);
    }       
}

@Override
public boolean hasStableIds() {
    return true;
}

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

private int CalculateRowCount (ExpandableListView parent ) {
    int count = 0;  
    //dig out the expanded child nodes in tree depth
    for (int i = 0; i < parent.getExpandableListAdapter().getGroupCount(); i++) {
        count++;
        if (parent.isGroupExpanded(i)) {
            count += GetFurtherChild(parent,i);
        }
    }   
    return count;
}

private int GetFurtherChild (ExpandableListView parent, int index){

    int count = parent.getExpandableListAdapter().getChildrenCount(index);
    ExpandableListView elv = null;

    for (int i=0; i<parent.getExpandableListAdapter().getChildrenCount(index); i++ ) {          
        try {//check if this is expandable list
            elv = (ExpandableListView)parent.getExpandableListAdapter().getChildView(index, i, false, null, parent);
            if (elv != null && elv.isGroupExpanded(0)) {
                count += GetFurtherChild(elv, 0);
            }
        } catch (Exception e) {
            Log.d("Exception", e.getMessage());
        }           
    }
    return count;
}

public void CreateData(HashMap<String, String> nodeData){

    // GET ID AND LEVEL OF PARENT NODE, LEVEL OF CHILD WILL BE LEVEL OF PARENT + 1
    Integer id = Integer.valueOf(nodeData.get("_id").toString());
    Integer level = Integer.valueOf(nodeData.get("level").toString()) + 1;

    groupData = new ArrayList<Map<String, String>>();
    childData = new ArrayList<List<Map<String, String>>>();

    // GET CHILD LIST. 
    list = data.get(level); 
    listSize = list.size();

    // PARENT NODE DATA IS ALREADY IN NODE DATA HASH MAP
    groupData.add(nodeData);

    // WE NEED TO CREATE CHILD DATA 
    children = new ArrayList<Map<String, String>>();
    childData.add(children);

    for (int i=0; i < listSize; i++) { 
        // GET THE DETAIL ARRAY 
        String [] levelDetail = list.get(i);

        // IF PARENT NODE ID AND CHILD NODE PARENT ID IS SAME THEN CREATE ENTRY
        if ( id == Integer.valueOf(levelDetail[1]) ) {

            childMap = new HashMap<String, String>();
            children.add(childMap);
            childMap.put("_id", levelDetail[0]);
            childMap.put("parentId", levelDetail[1]);
            childMap.put("name", levelDetail[2]);
            childMap.put("hasChild", levelDetail[3]);  
            childMap.put("level", String.valueOf(level));
        }
    }
}

class Level2GroupExpandListener implements ExpandableListView.OnGroupClickListener {

    @Override
    public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {
        if( parent.isGroupExpanded( groupPosition ) )
            parent.collapseGroup( groupPosition );
        else
            parent.expandGroup( groupPosition );

        if( parent instanceof CustomExpandableListView ) {
            CustomExpandableListView celv = (CustomExpandableListView)parent;
            Integer level = Integer.valueOf(((HashMap<String, String>) parent.getExpandableListAdapter().getGroup(groupPosition)).get("level").toString());
            celv.setRows(CalculateRowCount(celv));
            celv.requestLayout();

            if (level > 1) {
                while (((HashMap<String, String>)parent.getExpandableListAdapter().getGroup(0)).get("level").toString().equalsIgnoreCase("1") == false) {
                    parent = (ExpandableListView)parent.getParent();
                    celv = (CustomExpandableListView)parent;
                    celv.setRows(CalculateRowCount(parent));
                    celv.requestLayout();           
                }   
            }
        }
        topList.requestLayout();
        return true;
    }
}

您必须扩展两个类才能创建树视图。这是示例代码

package com.example.mytreeview;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ExpandableListView;
import android.widget.SimpleExpandableListAdapter;

public class CustomExpandableListAdapter extends SimpleExpandableListAdapter {

Context context = null;
ExpandableListView topList;
LayoutInflater inflater = null;
HashMap<Integer, ArrayList<String[]>> data;
ArrayList<Map<String, String>> groupData;
ArrayList<List<Map<String, String>>> childData;
List<Map<String, String>> children;
Map<String, String> childMap;
ArrayList<String[]> list;
int listSize;
HashMap<Integer, CustomExpandableListView> elvCache = new HashMap<Integer, CustomExpandableListView>();

public CustomExpandableListAdapter( Context context, 
        ExpandableListView topList, 
        HashMap<Integer, ArrayList<String[]>> data, 
        ArrayList<Map<String, String>> groupData, 
        ArrayList<List<Map<String, String>>> childData ) {      
    super(
            context,
            groupData,
            R.layout.grouprow,
            new String[] { "name", "_id", "parentId" },
            new int[] { R.id.tvLevelName, R.id.tvId, R.id.tvParentId },
            childData,
            R.layout.childrow,
            new String[] { "name", "_id", "parentId" },
            new int[] { R.id.tvLevelName, R.id.tvId, R.id.tvParentId }
    );  

    this.context = context;
    this.topList = topList;
    this.data = data;
    inflater = LayoutInflater.from(context);
}   

@Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {       

    // if there are no child nodes then simply show the single row  
    HashMap <String, String> levelinfo = (HashMap<String, String>)getChild(groupPosition, childPosition); 
    Integer levelId = Integer.valueOf(levelinfo.get("_id"));

    if (levelinfo.get("hasChild").toString().equalsIgnoreCase("N")) {
        View v = super.getChildView(groupPosition, childPosition, isLastChild, convertView, parent);            
        return v;   
    }
    else
    { // if the node contains child nodes then insert new expandable list           
        CustomExpandableListView v = null;

        v = elvCache.get(levelId);
        if (v == null) {
            CreateData(levelinfo);
            v = new CustomExpandableListView(context, null, android.R.attr.expandableListViewStyle);
            v.setRows(groupData.size());        
            v.setPadding(10, 0, 0, 0);
            v.setAdapter(new CustomExpandableListAdapter(context, topList, data, groupData, childData));
            v.setOnGroupClickListener(new Level2GroupExpandListener());
            elvCache.put(levelId, v);               
        }
        return super.getChildView(groupPosition, childPosition, isLastChild, v, parent);
    }       
}

@Override
public boolean hasStableIds() {
    return true;
}

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

private int CalculateRowCount (ExpandableListView parent ) {
    int count = 0;  
    //dig out the expanded child nodes in tree depth
    for (int i = 0; i < parent.getExpandableListAdapter().getGroupCount(); i++) {
        count++;
        if (parent.isGroupExpanded(i)) {
            count += GetFurtherChild(parent,i);
        }
    }   
    return count;
}

private int GetFurtherChild (ExpandableListView parent, int index){

    int count = parent.getExpandableListAdapter().getChildrenCount(index);
    ExpandableListView elv = null;

    for (int i=0; i<parent.getExpandableListAdapter().getChildrenCount(index); i++ ) {          
        try {//check if this is expandable list
            elv = (ExpandableListView)parent.getExpandableListAdapter().getChildView(index, i, false, null, parent);
            if (elv != null && elv.isGroupExpanded(0)) {
                count += GetFurtherChild(elv, 0);
            }
        } catch (Exception e) {
            Log.d("Exception", e.getMessage());
        }           
    }
    return count;
}

public void CreateData(HashMap<String, String> nodeData){

    // GET ID AND LEVEL OF PARENT NODE, LEVEL OF CHILD WILL BE LEVEL OF PARENT + 1
    Integer id = Integer.valueOf(nodeData.get("_id").toString());
    Integer level = Integer.valueOf(nodeData.get("level").toString()) + 1;

    groupData = new ArrayList<Map<String, String>>();
    childData = new ArrayList<List<Map<String, String>>>();

    // GET CHILD LIST. 
    list = data.get(level); 
    listSize = list.size();

    // PARENT NODE DATA IS ALREADY IN NODE DATA HASH MAP
    groupData.add(nodeData);

    // WE NEED TO CREATE CHILD DATA 
    children = new ArrayList<Map<String, String>>();
    childData.add(children);

    for (int i=0; i < listSize; i++) { 
        // GET THE DETAIL ARRAY 
        String [] levelDetail = list.get(i);

        // IF PARENT NODE ID AND CHILD NODE PARENT ID IS SAME THEN CREATE ENTRY
        if ( id == Integer.valueOf(levelDetail[1]) ) {

            childMap = new HashMap<String, String>();
            children.add(childMap);
            childMap.put("_id", levelDetail[0]);
            childMap.put("parentId", levelDetail[1]);
            childMap.put("name", levelDetail[2]);
            childMap.put("hasChild", levelDetail[3]);  
            childMap.put("level", String.valueOf(level));
        }
    }
}

class Level2GroupExpandListener implements ExpandableListView.OnGroupClickListener {

    @Override
    public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {
        if( parent.isGroupExpanded( groupPosition ) )
            parent.collapseGroup( groupPosition );
        else
            parent.expandGroup( groupPosition );

        if( parent instanceof CustomExpandableListView ) {
            CustomExpandableListView celv = (CustomExpandableListView)parent;
            Integer level = Integer.valueOf(((HashMap<String, String>) parent.getExpandableListAdapter().getGroup(groupPosition)).get("level").toString());
            celv.setRows(CalculateRowCount(celv));
            celv.requestLayout();

            if (level > 1) {
                while (((HashMap<String, String>)parent.getExpandableListAdapter().getGroup(0)).get("level").toString().equalsIgnoreCase("1") == false) {
                    parent = (ExpandableListView)parent.getParent();
                    celv = (CustomExpandableListView)parent;
                    celv.setRows(CalculateRowCount(parent));
                    celv.requestLayout();           
                }   
            }
        }
        topList.requestLayout();
        return true;
    }
}

}

package com.example.mytreeview;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;
import android.widget.ExpandableListView;

public class CustomExpandableListView extends ExpandableListView {

public static int ROW_HEIGHT;
private int rows;

public CustomExpandableListView(Context context, AttributeSet attrs, int defStyle) {
    super( context, attrs, defStyle );

    if (Main.screenSize == ScreenSize.NARROW)
        ROW_HEIGHT = 45;
    else
        ROW_HEIGHT = 31;
}

public void setRows( int rows ) {
    this.rows = rows;
}

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    setMeasuredDimension( getMeasuredWidth(), rows*ROW_HEIGHT);

}

protected void onLayout (boolean changed, int left, int top, int right, int bottom) {
    super.onLayout( changed, left,top,right,bottom );
}

private String decodeMeasureSpec( int measureSpec ) {
    int mode = View.MeasureSpec.getMode( measureSpec );
    String modeString = "<> ";
    switch( mode ) {
    case View.MeasureSpec.UNSPECIFIED:
        modeString = "UNSPECIFIED ";
        break;

    case View.MeasureSpec.EXACTLY:
        modeString = "EXACTLY ";
        break;

    case View.MeasureSpec.AT_MOST:
        modeString = "AT_MOST ";
        break;
    }
    return modeString+Integer.toString( View.MeasureSpec.getSize( measureSpec ) );
}


}


package com.example.mytreeview;

public enum ScreenSize {
NARROW, 
WIDE
}
}

package com.example.mytreeview;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;
import android.widget.ExpandableListView;

public class CustomExpandableListView extends ExpandableListView {

public static int ROW_HEIGHT;
private int rows;

public CustomExpandableListView(Context context, AttributeSet attrs, int defStyle) {
    super( context, attrs, defStyle );

    if (Main.screenSize == ScreenSize.NARROW)
        ROW_HEIGHT = 45;
    else
        ROW_HEIGHT = 31;
}

public void setRows( int rows ) {
    this.rows = rows;
}

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    setMeasuredDimension( getMeasuredWidth(), rows*ROW_HEIGHT);

}

protected void onLayout (boolean changed, int left, int top, int right, int bottom)          {
    super.onLayout( changed, left,top,right,bottom );
}

private String decodeMeasureSpec( int measureSpec ) {
    int mode = View.MeasureSpec.getMode( measureSpec );
    String modeString = "<> ";
    switch( mode ) {
    case View.MeasureSpec.UNSPECIFIED:
        modeString = "UNSPECIFIED ";
        break;

    case View.MeasureSpec.EXACTLY:
        modeString = "EXACTLY ";
        break;

    case View.MeasureSpec.AT_MOST:
        modeString = "AT_MOST ";
        break;
    }
    return modeString+Integer.toString( View.MeasureSpec.getSize( measureSpec ) );
}


}


package com.example.mytreeview;

public enum ScreenSize {
NARROW, 
WIDE
}