TreeView就像功能Android一样

时间:2013-09-09 12:35:25

标签: android android-listview treeview expandablelistview

我正在为我的应用实施TreeView。 我在网上搜索过,发现一个ListView实施TreeView太乱了。是否可以使用TreeView实现n级ExpandableListView

请分享您的想法或参考我的一些例子。

先谢谢。

3 个答案:

答案 0 :(得分:4)

我很久以前用ListView解决了我的问题。有些人遇到同样的问题并要我分享我的solution,所以我在这里。

TreeElementI.java

public interface TreeElementI extends Serializable{
  public void addChild(TreeElementI child);
  public String getId();
  public void setId(String id);
  public String getOutlineTitle();
  public void setOutlineTitle(String outlineTitle);
  public boolean isHasParent();
  public void setHasParent(boolean hasParent);
  public boolean isHasChild();
  public void setHasChild(boolean hasChild);
  public int getLevel();
  public void setLevel(int level);
  public boolean isExpanded();
  public void setExpanded(boolean expanded);
  public ArrayList<TreeElementI> getChildList();
  public TreeElementI getParent();
  public void setParent(TreeElementI parent);
}

TreeElement.java

public class TreeElement implements TreeElementI{
private String id;
private String outlineTitle;
private boolean hasParent;
private boolean hasChild;
private TreeElementI parent;
private int level;
private ArrayList<TreeElementI> childList;
private boolean expanded;

public TreeElement(String id, String outlineTitle) {
    super();
    this.childList = new ArrayList<TreeElementI>();
    this.id = id;
    this.outlineTitle = outlineTitle;
    this.level = 0;
    this.hasParent = true;
    this.hasChild = false;
    this.parent = null;
}

public TreeElement(String id, String outlineTitle, boolean hasParent, boolean hasChild, TreeElement parent, int level, boolean expanded) {
    super();
    this.childList = new ArrayList<TreeElementI>();
    this.id = id;
    this.outlineTitle = outlineTitle;
    this.hasParent = hasParent;
    this.hasChild = hasChild;
    this.parent = parent;
    if(parent != null) {
        this.parent.getChildList().add(this);
    }
    this.level = level;
    this.expanded = expanded;
}

@Override
public void addChild(TreeElementI child) {
    this.getChildList().add(child);
    this.setHasParent(false);
    this.setHasChild(true);
    child.setParent(this);
    child.setLevel(this.getLevel() + 1);
}

@Override
public String getId() {
    return this.id;
}

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

@Override
public String getOutlineTitle() {
    return this.outlineTitle;
}

@Override
public void setOutlineTitle(String outlineTitle) {
    this.outlineTitle = outlineTitle;
}

@Override
public boolean isHasParent() {
    return this.hasParent;
}

@Override
public void setHasParent(boolean hasParent) {
    this.hasParent = hasParent;
}

@Override
public boolean isHasChild() {
    return this.hasChild;
}

@Override
public void setHasChild(boolean hasChild) {
    this.hasChild = hasChild;
}

@Override
public int getLevel() {
    return this.level;
}

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

@Override
public boolean isExpanded() {
    return this.expanded;
}

@Override
public void setExpanded(boolean expanded) {
    this.expanded = expanded;
}

@Override
public ArrayList<TreeElementI> getChildList() {
    return this.childList;
}

@Override
public TreeElementI getParent() {
    return this.parent;
}

@Override
public void setParent(TreeElementI parent) {
    this.parent = parent;
}
}

TreeViewClassifAdapter.java

public class TreeViewClassifAdapter extends BaseAdapter {
private static final int TREE_ELEMENT_PADDING_VAL = 25;
private List<TreeElementI> fileList;
private Context context;
private Bitmap iconCollapse;
private Bitmap iconExpand;
private Dialog dialog;
private EditText textLabel;
private XTreeViewClassif treeView;

public TreeViewClassifAdapter(Context context, List<TreeElementI> fileList, Dialog dialog, EditText textLabel, XTreeViewClassif treeView) {
    this.context = context;
    this.fileList = fileList;
    this.dialog = dialog;
    this.textLabel = textLabel;
    this.treeView = treeView;
    iconCollapse = BitmapFactory.decodeResource(context.getResources(), R.drawable.x_treeview_outline_list_collapse);
    iconExpand = BitmapFactory.decodeResource(context.getResources(), R.drawable.x_treeview_outline_list_expand);
}

public List<TreeElementI> getListData() {
    return this.fileList;
}

@Override
public int getCount() {
    return this.fileList.size();
}

@Override
public Object getItem(int position) {
    return this.fileList.get(position);
}

@Override
public long getItemId(int position) {
    return position;
}

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

    convertView = View.inflate(context, R.layout.x_treeview_classif_list_item, null);
    holder = new ViewHolder();
    holder.setTextView((TextView) convertView.findViewById(R.id.text));
    holder.setImageView((ImageView) convertView.findViewById(R.id.icon));
    convertView.setTag(holder);

    final TreeElementI elem = (TreeElementI) getItem(position);

    int level = elem.getLevel();
    holder.getIcon().setPadding(TREE_ELEMENT_PADDING_VAL * (level + 1), holder.icon.getPaddingTop(), 0, holder.icon.getPaddingBottom());
    holder.getText().setText(elem.getOutlineTitle());
    if (elem.isHasChild() && (elem.isExpanded() == false)) {
        holder.getIcon().setImageBitmap(iconCollapse);
    } else if (elem.isHasChild() && (elem.isExpanded() == true)) {
        holder.getIcon().setImageBitmap(iconExpand);
    } else if (!elem.isHasChild()) {
        holder.getIcon().setImageBitmap(iconCollapse);
        holder.getIcon().setVisibility(View.INVISIBLE);
    }

    IconClickListener iconListener = new IconClickListener(this, position);
    TextClickListener txtListener = new TextClickListener((ArrayList<TreeElementI>) this.getListData(), position);
    holder.getIcon().setOnClickListener(iconListener);
    holder.getText().setOnClickListener(txtListener);
    return convertView;
}

private class ViewHolder {
    ImageView icon;
    TextView text;

    public TextView getText() {
        return this.text;
    }

    public void setTextView(TextView text) {
        this.text = text;
    }

    public ImageView getIcon() {
        return this.icon;
    }

    public void setImageView(ImageView icon) {
        this.icon = icon;
    }
}

/**
 * Listener For TreeElement Text Click
 */
private class TextClickListener implements View.OnClickListener {
    private ArrayList<TreeElementI> list;
    private int position;

    public TextClickListener(ArrayList<TreeElementI> list, int position) {
        this.list = list;
        this.position = position;
    }

    @Override
    public void onClick(View v) {
        treeView.setXValue(String.valueOf(list.get(position).getId()));
        dialog.dismiss();
    }
}

/**
 * Listener for TreeElement "Expand" button Click
 */
private class IconClickListener implements View.OnClickListener {
    private ArrayList<TreeElementI> list;
    private TreeViewClassifAdapter adapter;
    private int position;

    public IconClickListener(TreeViewClassifAdapter adapter, int position) {
        this.list = (ArrayList<TreeElementI>) adapter.getListData();
        this.adapter = adapter;
        this.position = position;
    }

    @Override
    public void onClick(View v) {
        if (!list.get(position).isHasChild()) {
            return;
        }

        if (list.get(position).isExpanded()) {
            list.get(position).setExpanded(false);
            TreeElementI element = list.get(position);
            ArrayList<TreeElementI> temp = new ArrayList<TreeElementI>();

            for (int i = position + 1; i < list.size(); i++) {
                if (element.getLevel() >= list.get(i).getLevel()) {
                    break;
                }
                temp.add(list.get(i));
            }
            list.removeAll(temp);
            adapter.notifyDataSetChanged();
        } else {
            TreeElementI obj = list.get(position);
            obj.setExpanded(true);
            int level = obj.getLevel();
            int nextLevel = level + 1;

            for (TreeElementI element : obj.getChildList()) {
                element.setLevel(nextLevel);
                element.setExpanded(false);
                list.add(position + 1, element);
            }
            adapter.notifyDataSetChanged();
        }
    }
}
}

答案 1 :(得分:1)

This google的项目将有助于将其用作外部Android库。取消设置“isLibrary?”后flag,项目也可以自己编译和安装 - 提供演示小部件功能的演示应用程序。它显示了树如何动态行为,包括为多个/所有节点解释和折叠节点,为树提供上下文菜单,自定义树视图,仅具有可用于叶节点的复选框,自定义着色和用于树的不同级别的文本的不同文本大小这棵树(虽然丑陋)。

希望这有助于......:)

答案 2 :(得分:0)

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

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
}