zoukankan      html  css  js  c++  java
  • Android中的树状(tree)列表

    树状列表前端挺常用的,还有人专门写过Ztree,Android中有的时候也需要使用到树状列表,上篇文章写了一下ExpandableListView,ExpandableListView最多支持两级结构,Android中没有三层结构的组件,这个时候需要自己去扩展,可以扩展ExpandableListView,也可以选择扩展ListView。个人觉得扩展ListView更简单一点,多级列表你可以一次性加载出来,也可以分级加载出来,一般分级比较好,点了某一级可以控制点击事件然后去加载子级,这样实现起来会想容易一点,也好理解一点。

    基础维护

    新建一个activity_tree.xml布局文件,里面放一个单独的ListView:

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="com.example.googletree.TreeActivity" >
    
      <ListView 
            android:id="@+id/tree_list"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
    
    
    </RelativeLayout>
    

     tree_item布局文件,其中包括一个图片,一个文本:

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
        
           <ImageView 
            android:id="@+id/homeImg"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_alignParentLeft="true"/>
        
        <TextView 
            android:id="@+id/treeText"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_toRightOf="@id/homeImg"/>
        
    
    </RelativeLayout>
    

     Demo实现

    需要展示一个树状结构的数据,先定义一个TreeNode类,需要展示数据其中主要讲下几个字段,父级和子级之间的关系你可以用ParentId判断也可以使用Code来区分,看个人喜好:

    文本:contentText

    ID号:ID

    ParentId:父级ID

    hasChildren:判断是不是末级

    isExpanded:item是否展开

    public class TreeNode {
    	/** 文字内容 */
    	private String contentText;
    	/** 在tree中的层级 */
    	private int level;
    	/** 元素的id */
    	private int id;
    	/** 父元素的id */
    	private int parendId;
    	/** 是否有子元素 */
    	private boolean hasChildren;
    	/** item是否展开 */
    	private boolean isExpanded;
    	
    	/** 表示该节点没有父元素,也就是level为0的节点 */
    	public static final int NO_PARENT = -1;
    	/** 表示该元素位于最顶层的层级 */
    	public static final int TOP_LEVEL = 0;
    	
    	public TreeNode(String contentText, int level, int id, int parendId,
    			boolean hasChildren, boolean isExpanded) {
    		super();
    		this.contentText = contentText;
    		this.level = level;
    		this.id = id;
    		this.parendId = parendId;
    		this.hasChildren = hasChildren;
    		this.isExpanded = isExpanded;
    	}
    
    	public boolean isExpanded() {
    		return isExpanded;
    	}
    
    	public void setExpanded(boolean isExpanded) {
    		this.isExpanded = isExpanded;
    	}
    
    	public String getContentText() {
    		return contentText;
    	}
    
    	public void setContentText(String contentText) {
    		this.contentText = contentText;
    	}
    
    	public int getLevel() {
    		return level;
    	}
    
    	public void setLevel(int level) {
    		this.level = level;
    	}
    
    	public int getId() {
    		return id;
    	}
    
    	public void setId(int id) {
    		this.id = id;
    	}
    
    	public int getParendId() {
    		return parendId;
    	}
    
    	public void setParendId(int parendId) {
    		this.parendId = parendId;
    	}
    
    	public boolean isHasChildren() {
    		return hasChildren;
    	}
    
    	public void setHasChildren(boolean hasChildren) {
    		this.hasChildren = hasChildren;
    	}
    }
    

     为了填充视图的中ListView,需要自定义TreeAdapter,之前的文章关于ListView中使用Adapter介绍过,如果需要具体怎么使用的可以看下之前的文章,主要使用了一个ViewHolder的优化:

    public class TreeAdapter extends BaseAdapter {
    	/** 所有的数据集合 */
    	private ArrayList<TreeNode> allNodes;
    	/** 顶层元素结合*/
    	private ArrayList<TreeNode> topNodes;
    	/** LayoutInflater */
    	private LayoutInflater inflater;
    	/** item的行首缩进基数 */
    	private int indentionBase;
    	
    	public TreeViewAdapter(ArrayList<TreeNode> topNodes, ArrayList<TreeNode> allNodes, LayoutInflater inflater) {
    		this.topNodes = topNodes;
    		this.allNodes = allNodes;
    		this.inflater = inflater;
    		indentionBase =20;
    	}
    	public ArrayList<TreeNode> getTopNodes() {
    		return topNodes;
    	}
    	
    	public ArrayList<TreeNode> getAllNodes() {
    		return allNodes;
    	}
    	
    	@Override
    	public int getCount() {
    		return topNodes.size();
    	}
    
    	@Override
    	public Object getItem(int position) {
    		return topNodes.get(position);
    	}
    
    	@Override
    	public long getItemId(int position) {
    		return position;
    	}
    
    	@Override
    	public View getView(int position, View convertView, ViewGroup parent) {
    		ViewHolder holder = null;
    		if (convertView == null) {
    			holder = new ViewHolder();
    			convertView = inflater.inflate(R.layout.tree_item, null);
    			holder.homeImg = (ImageView) convertView.findViewById(R.id.homeImg);
    			holder.treeText = (TextView) convertView.findViewById(R.id.treeText);
    			convertView.setTag(holder);
    		} else {
    			holder = (ViewHolder) convertView.getTag();
    		}
    		TreeNode element = topNodes.get(position);
    		int level =element.getLevel();
    		holder.homeImg.setPadding(
    				indentionBase * (level + 1), 
    				holder.homeImg.getPaddingTop(), 
    				holder.homeImg.getPaddingRight(), 
    				holder.homeImg.getPaddingBottom());
    		holder.treeText.setText(element.getContentText());
    		if (element.isHasChildren() && !element.isExpanded()) {
    			holder.homeImg.setImageResource(R.drawable.open);
    			//这里要主动设置一下icon可见,因为convertView有可能是重用了"设置了不可见"的view,下同。
    			holder.homeImg.setVisibility(View.VISIBLE);
    		} else if (element.isHasChildren() && element.isExpanded()) {
    			holder.homeImg.setImageResource(R.drawable.open);
    			holder.homeImg.setVisibility(View.VISIBLE);
    		} else if (!element.isHasChildren()) {
    			holder.homeImg.setImageResource(R.drawable.open);
    			holder.homeImg.setVisibility(View.VISIBLE);
    		}
    		return convertView;
    	}
    	
    	static class ViewHolder{
    		ImageView homeImg;
    		TextView treeText;
    	}
    }
    

    由于每次都是加载一层节点,需要自己控制点击事件,自定义一个TreeItemClickListener来监听事件:

    public class TreeItemClickListener implements OnItemClickListener {
    	/** 定义的适配器 */
    	private TreeViewAdapter treeViewAdapter;
    	
    	public TreeViewItemClickListener(TreeViewAdapter treeViewAdapter) {
    		this.treeViewAdapter = treeViewAdapter;
    	}
    	
    	@Override
    	public void onItemClick(AdapterView<?> parent, View view, int position,
    			long id) {
    		//点击的item代表的元素
    		TreeNode treeNode = (TreeNode) treeViewAdapter.getItem(position);
    		//树中顶层的元素
    		ArrayList<TreeNode> topNodes = treeViewAdapter.getTopNodes();
    		//元素的数据源
    		ArrayList<TreeNode> allNodes = treeViewAdapter.getAllNodes();
    		
    		//点击没有子项的item直接返回
    		if (!treeNode.isHasChildren()) {
    			return;
    		}
    		
    		if (treeNode.isExpanded()) {
    			treeNode.setExpanded(false);
    			//删除节点内部对应子节点数据,包括子节点的子节点...
    			ArrayList<TreeNode> elementsToDel = new ArrayList<TreeNode>();
    			for (int i = position + 1; i < topNodes.size(); i++) {
    				if (treeNode.getLevel() >= topNodes.get(i).getLevel())
    					break;
    				elementsToDel.add(topNodes.get(i));
    			}
    			topNodes.removeAll(elementsToDel);
    			treeViewAdapter.notifyDataSetChanged();
    		} else {
    			treeNode.setExpanded(true);
    			//从数据源中提取子节点数据添加进树,注意这里只是添加了下一级子节点,为了简化逻辑
    			int i = 1;//注意这里的计数器放在for外面才能保证计数有效
    			for (TreeNode e : allNodes) {
    				if (e.getParendId() == treeNode.getId()) {
    					e.setExpanded(false);
    					topNodes.add(position + i, e);
    					i ++;
    				}
    			}
    			treeViewAdapter.notifyDataSetChanged();
    		}
    	}
    
    }
    

     activity初始化数据:

    private void init() {
    		topNodes = new ArrayList<TreeNode>();
    		allNodes = new ArrayList<TreeNode>();
    		
    		//添加节点  -- 节点名称,节点level,节点id,父节点id,是否有子节点,是否展开
    		
    		//添加最外层节点
    		TreeNode node1= new TreeNode("北京市", TreeNode.TOP_LEVEL, 0, TreeNode.NO_PARENT, true, false);
    		
    		//添加第一层节点
    		TreeNode node2= new TreeNode("海淀区", TreeNode.TOP_LEVEL + 1, 1, node1.getId(), true, false);
    		//添加第二层节点
    		TreeNode node3= new TreeNode("西二旗", TreeNode.TOP_LEVEL + 2, 2, node2.getId(), true, false);
    		//添加第三层节点
    //		TreeNode node7= new TreeNode("辉煌国际", TreeNode.TOP_LEVEL + 3, 6, node3.getId(), false, false);
    	
    		
    		//添加第一层节点
    		TreeNode node4= new TreeNode("河南省", TreeNode.TOP_LEVEL , 3, TreeNode.NO_PARENT, true, false);
    		//添加第二层节点
    		TreeNode node5= new TreeNode("郑州市", TreeNode.TOP_LEVEL + 1, 4, node4.getId(), true, false);
    		//添加第三层节点
    		TreeNode node6= new TreeNode("金水区", TreeNode.TOP_LEVEL + 2, 5, node5.getId(), false, false);
    				
    		//添加初始树元素
    		topNodes.add(node1);
    		topNodes.add(node4);
    		//创建数据源
    		allNodes.add(node1);
    		allNodes.add(node2);
    		allNodes.add(node3);
    		allNodes.add(node4);
    		allNodes.add(node5);
    		allNodes.add(node6);
    //		allNodes.add(node7);
    	}
    

     oncreate方法中调用:

    	LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    		
    		init();
    		
    		ListView treeview = (ListView) findViewById(R.id.tree_list);
    		TreeViewAdapter treeViewAdapter = new TreeViewAdapter(topNodes, allNodes, inflater);
    		TreeViewItemClickListener treeViewItemClickListener = new TreeViewItemClickListener(treeViewAdapter);
    		treeview.setAdapter(treeViewAdapter);
    		treeview.setOnItemClickListener(treeViewItemClickListener);
    

      效果如下:

    全部展开:

     这个时候把treeActivity中那个node7注释取消,也就是加了第三层节点的效果:

    TreeNode node7= new TreeNode("辉煌国际", TreeNode.TOP_LEVEL + 3, 6, node3.getId(), false, false);	

      效果如下:

  • 相关阅读:
    mysql 一
    scanf函数的返回值问题
    统计一个数分解质因数中不同因子的个数
    统计一个数分解质因数中不同因子的个数
    统计一个数分解质因数中不同因子的个数
    GridControl控件和TreeList控件设置标志图
    GridControl控件和TreeList控件设置标志图
    GridControl控件和TreeList控件设置标志图
    btn按钮之间事件相互调用
    btn按钮之间事件相互调用
  • 原文地址:https://www.cnblogs.com/xiaofeixiang/p/4109969.html
Copyright © 2011-2022 走看看