Android 树形菜单

时间:2023-03-08 22:17:27

首先来一张萌萌哒的效果图(比较懒 - -)

Android 树形菜单

然后是代码:

//  Node
package com.example.treeview.utils; import java.util.ArrayList;
import java.util.List; public class Node { public Node() {
super();
} public Node(int id, int pId, String name) {
super();
this.id = id;
this.pId = pId;
this.name = name;
} private int id;
/**
* 根节点的层级
*/
private int pId = 0;
private String name;
/**
* 树的层级
*/
private int level;
/**
* 是否展开
*/
private boolean isExpand = false;
private int icon; private Node parent;
private List<Node> children = new ArrayList<Node>(); /**
* 判断是否为根节点
*
* @return
*/
public boolean isRoot() {
return parent == null;
} public int getId() {
return id;
} /**
* 判断当前父节点是否展开
*
* @return
*/
public boolean isparentExpand() {
if (parent == null) {
return false;
} else {
return parent.isExpand;
}
} /**
* 判断是否为叶节点
*
* @return
*/
public boolean isLeaf() {
return children.size() == 0;
} public void setId(int id) {
this.id = id;
} public int getpId() {
return pId;
} public void setpId(int pId) {
this.pId = pId;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} /**
* 得到当前节点的层级
*
* @return
*/
public int getLevel() {
return parent == null ? 0 : parent.getLevel() + 1;
} public void setLevel(int level) {
this.level = level;
} public boolean isExpand() {
return isExpand;
} public void setExpand(boolean isExpand) {
this.isExpand = isExpand;
if (isExpand) {
for (Node node : children) {
node.setExpand(false);
}
}
} public int getIcon() {
return icon;
} public void setIcon(int icon) {
this.icon = icon;
} public Node getParent() {
return parent;
} public void setParent(Node parent) {
this.parent = parent;
} public List<Node> getChildren() {
return children;
} public void setChildren(List<Node> children) {
this.children = children;
} }
//FileBean
package com.example.treeview.bean; import com.example.treeview.utils.annotation.TreeNodeId;
import com.example.treeview.utils.annotation.TreeNodeLable;
import com.example.treeview.utils.annotation.TreeNodePid; public class FileBean { @TreeNodeId
private int id;
@TreeNodePid
private int pId;
@TreeNodeLable
private String label; public FileBean(int id, int pId, String label) {
super();
this.id = id;
this.pId = pId;
this.label = label;
} private String desc;
}
// 注解
package com.example.treeview.utils.annotation; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; @Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME.RUNTIME)
public @interface TreeNodeId { } package com.example.treeview.utils.annotation; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; @Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME.RUNTIME)
public @interface TreeNodeLable { } package com.example.treeview.utils.annotation; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; @Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME.RUNTIME)
public @interface TreeNodePid { }
//TreeHelper
package com.example.treeview.utils; import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List; import com.example.treeview.utils.annotation.TreeNodeId;
import com.example.treeview.utils.annotation.TreeNodeLable;
import com.example.treeview.utils.annotation.TreeNodePid; public class TreeHelper { /**
* 将用户的数据转化为树形数据
*
* @param datas
* @return
* @throws IllegalArgumentException
* @throws IllegalAccessException
*/
public static <T> List<Node> convertDatasNodes(List<T> datas)
throws IllegalAccessException, IllegalArgumentException {
List<Node> nodes = new ArrayList<Node>();
Node node = null;
for (T t : datas) { int id = -1;
int pId = -1;
String lable = null;
node = new Node();
Class clazz = t.getClass();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if (field.getAnnotation(TreeNodeId.class) != null) {
field.setAccessible(true);
id = field.getInt(t);
}
if (field.getAnnotation(TreeNodePid.class) != null) {
field.setAccessible(true);
pId = field.getInt(t);
}
if (field.getAnnotation(TreeNodeLable.class) != null) {
field.setAccessible(true);
lable = (String) field.get(t);
}
}
node = new Node(id, pId, lable);
nodes.add(node);
}
/**
*
* 设置节点间的关系
*/
for (int i = 0; i < nodes.size(); i++) {
Node n=nodes.get(i);
for (int j =i+1; j <nodes.size(); j++) {
Node m=nodes.get(j);
if (m.getpId()==n.getId()) {
n.getChildren().add(m);
m.setParent(n);
}else if (m.getId()==n.getpId()) {
m.getChildren().add(n);
n.setParent(m);
}
}
} for (Node n:nodes) {
setNodeIcon(n);
}
return nodes;
} /**
* 设置过滤出可见的节点
* @param nodes
* @return
*/
public static List<Node> filterVisibleNodeS(List<Node> nodes){
List<Node> reuslt=new ArrayList<Node>();
for (Node node : nodes) {
if (node.isRoot()||node.isparentExpand()) {
setNodeIcon(node);
reuslt.add(node);
}
}
return reuslt;
} /**
*
* @param datas
* @return
* @throws IllegalArgumentException
* @throws IllegalAccessException
*/
public static <T> List<Node> getSortedNodes(List<T> datas,int defaultExpandLevel) throws IllegalAccessException, IllegalArgumentException{
List<Node> result=new ArrayList<Node>();
List<Node> nodes=convertDatasNodes(datas);
List<Node> rootNodes=getRootNodes(nodes);
for (Node node : rootNodes) {
AddNode(result,node,defaultExpandLevel,1);
}
return result;
} /**
* 把一个节点的所有孩子节点都放入result
* @param result
* @param node
* @param defaultExpandLevel
* @param currentLevel
*/
private static void AddNode(List<Node> result, Node node,
int defaultExpandLevel, int currentLevel) {
result.add(node);
if (defaultExpandLevel>=currentLevel) {
node.setExpand(true);
}
if (node.isLeaf()) {
return;
}
for (int i = 0; i < node.getChildren().size(); i++) {
AddNode(result, node.getChildren().get(i), defaultExpandLevel, currentLevel+1);
}
} /**
* 从所有节点中过滤出根节点
* @param nodes
* @return
*/
private static List<Node> getRootNodes(List<Node> nodes) {
List<Node> root=new ArrayList<Node>();
for (Node node : nodes) {
if (node.isRoot()) {
root.add(node);
}
}
return root;
} /**
* 为Node设置图标
* @param n
*/
private static void setNodeIcon(Node n) {
if (n.getChildren().size()>0&&n.isExpand()) {
n.setIcon(0);
}else if(n.getChildren().size()>0&&!n.isExpand()){
n.setIcon(1);
}else {
n.setIcon(-1);
}
}
}
//TreeListViewAdapter
package com.example.treeview.adapter; import java.util.List; import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.ListView; import com.example.treeview.utils.Node;
import com.example.treeview.utils.TreeHelper; public abstract class TreeListViewAdapter<T> extends BaseAdapter { protected Context mContext;
protected List<Node> mAllNodes;
protected List<Node> mVisibleNodes;
protected LayoutInflater mInflater;
protected ListView mTree; /**
* 设置Node的点击回调
*
* @author az
*
*/
private interface OnTreeNodeClickListener {
void onClick(Node node, int position);
} private OnTreeNodeClickListener mListener; public void setOnTreeNodeClickListener(OnTreeNodeClickListener mListener) {
this.mListener = mListener;
} public OnTreeNodeClickListener getmListener() {
return mListener;
} public void setmListener(OnTreeNodeClickListener mListener) {
this.mListener = mListener;
} public TreeListViewAdapter(ListView mTree, Context context, List<T> datas,
int defaultExpandLevel) throws IllegalAccessException,
IllegalArgumentException {
this.mContext = context;
this.mInflater = LayoutInflater.from(context);
this.mAllNodes = TreeHelper.getSortedNodes(datas, defaultExpandLevel);
this.mVisibleNodes = TreeHelper.filterVisibleNodeS(mAllNodes);
this.mTree = mTree;
this.mTree.setOnItemClickListener(new OnItemClickListener() { @Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
expandOrCollapse(position);
if (mListener != null) {
mListener.onClick(mVisibleNodes.get(position), position);
}
}
});
} /**
* 点击收缩或者展开
*
* @param position
*/
private void expandOrCollapse(int position) {
Node n = mVisibleNodes.get(position);
if (n != null) {
if (n.isLeaf())
return;
n.setExpand(!n.isExpand());
mVisibleNodes = TreeHelper.filterVisibleNodeS(mAllNodes);
notifyDataSetChanged();
}
} @Override
public int getCount() {
return mVisibleNodes.size();
} @Override
public Object getItem(int position) {
return mVisibleNodes.get(position);
} @Override
public long getItemId(int position) {
return position;
} @Override
public View getView(int position, View convertView, ViewGroup parent) {
Node node=mVisibleNodes.get(position);
convertView=getConvertView(node, position, convertView, parent);
convertView.setPadding(node.getLevel()*30, 3, 3,3);
return convertView;
} public abstract View getConvertView(Node node,int position,View convertView,ViewGroup parent); }
//SimpleTreeListViewAdapter   继承TreeLivewAdapter方便使用
package com.example.treeview.adapter; import java.util.List; import com.example.threeview.R;
import com.example.treeview.utils.Node; import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView; public class SimpleTreeListViewAdapter<T> extends TreeListViewAdapter<T> { public SimpleTreeListViewAdapter(ListView mTree, Context context,
List<T> datas, int defaultExpandLevel)
throws IllegalAccessException, IllegalArgumentException {
super(mTree, context, datas, defaultExpandLevel);
// TODO Auto-generated constructor stub
} @Override
public View getConvertView(Node node, int position, View convertView,
ViewGroup parent) {
ViewHolder holder=null;
if (convertView==null) {
convertView=mInflater.inflate(R.layout.list_item, parent,false);
holder=new ViewHolder();
holder.mIcon=(ImageView) convertView.findViewById(R.id.iv_itemicon);
holder.mText=(TextView) convertView.findViewById(R.id.tv_itemtext);
convertView.setTag(holder);
}else {
holder=(ViewHolder) convertView.getTag();
}
holder.mText.setText(node.getName());
return convertView;
} private class ViewHolder{
ImageView mIcon;
TextView mText;
} }
//MainActivity

package com.example.treeview;

import java.util.ArrayList;
import java.util.List; import com.example.threeview.R;
import com.example.treeview.adapter.SimpleTreeListViewAdapter;
import com.example.treeview.bean.FileBean; import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ListView; public class MainActivity extends Activity { private ListView mTree;
private SimpleTreeListViewAdapter<FileBean> mAdapter;
private List<FileBean> mDatas;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTree=(ListView) findViewById(R.id.lv);
initDatas();
try {
mAdapter=new SimpleTreeListViewAdapter<>(mTree, this, mDatas, 0);
mTree.setAdapter(mAdapter);
} catch (IllegalAccessException | IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} }
private void initDatas() {
mDatas=new ArrayList<FileBean>();
FileBean bean=new FileBean(1, 0, "根1");
mDatas.add(bean);
bean=new FileBean(2, 0, "根2");
mDatas.add(bean);
bean=new FileBean(3, 1, "根1-1");
mDatas.add(bean);
bean=new FileBean(4, 2, "根2-1");
mDatas.add(bean);
} }

在上面的adapter里面有自定义的一个,使用方法:

mAdapter.setOnTreeNodeClickListener(new );

提供了一个OnClick方法:

onClick(Node node, int position)

参考:http://www.imooc.com/learn/303