我正在为我的应用实施TreeView
。
我在网上搜索过,发现一个ListView
实施TreeView
太乱了。是否可以使用TreeView
实现n级ExpandableListView
?
请分享您的想法或参考我的一些例子。
先谢谢。
答案 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
}