Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 樹形ListView

樹形ListView

編輯:關於Android編程

第一次接觸樹形ListView是一年前,當時公司做的項目是一個企業的員工管理軟件,在展示員工時用到的,我花了大半天時間,才把樹形ListView搞明白,完成任務後就沒有然後了(當時主管還對我說要注意代碼的積累,可我沒在意)。今年五月份來北京找工作,找了兩個月才找到工作(對這份工作還不能滿意,沒辦法還得要吃飯),這兩個月,浮躁的心也靜下來了,做技術的就踏踏實實的把技術搞好,再去想其他的。廢話不多說了說下這個樹形ListView吧,做了些封裝,只要明白原理,用的時候只需根據自己的需求修改些地方就可以了。 我封裝的這個樹形ListView針對數據是有從屬關系的數據。 針對數據, 第一步:將數據通過反射和注解轉化為想要的數據 第二步:理清數據關系(簡單說,就是找出誰是誰的爹,誰是誰的兒) 第三步:將數據排序(要知道ListView是將數據源裡的數據挨個展現出來的,所以順序很重要) 這是針對數據的操作 怎麼將樹形層級展示出來呢?通過View 的位置的後移做到的,層級越高,放的距離越遠離屏幕左方(一個固定距離*層級數) 如何實現展開和縮放(展開一些子節點就會展示出來,收縮一些數據就會隱藏) 通過兩個數據源,一個數據源為顯示的數據源,另一個為全部數據源,根據結點狀態過濾出顯示數據源。 上面這些就是樹形ListView的大體思想 首先介紹下代碼結構 \     MainActivity,SimpleTreeAdapter,FileNode只是些使用時的一些類, Node,TreeHelper,TreeListViewAdapter等這些是我們封裝的 首先說下Node,Node的類是我們封裝的數據源,我們要將數據轉化為Node類
	int id;
	int pid = 0;
	/**
	 *名稱
	 */
	String label;
	/**
	 * 層級
	 */
	int level;
	/**
	 * 當前是否展開
	 */
	private boolean isExpand =false;
	int index;
	private int icon;
	Node parent;
	List children =  new ArrayList();
	
	public Node(int id, int pid, String label) {
		super();
		this.id = id;
		this.pid = pid;
		this.label = label;
	}
	
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public int getPid() {
		return pid;
	}
	public void setPid(int pid) {
		this.pid = pid;
	}
	public String getLabel() {
		return label;
	}
	public void setLabel(String label) {
		this.label = label;
	}
	/**
	 * 節點的層級
	 * @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 n :children){
				n.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 getChildren() {
		return children;
	}
	public void setChildren(List children) {
		this.children = children;
	}
	/**
	 * 判斷是否是根節點
	 */
	public boolean isRoot(){
		return parent == null;
	}
	/**
	 * 父節點是否展開
	 * @return
	 */
	public boolean isParentExpand(){
		if(parent == null)
			return true;
		return  parent.isExpand();
	}
	/**
	 * 是否是葉節點
	 * @return
	 */
	public boolean isLeaf(){
		return children.size() == 0;
	}
	public int getIndex() {
		return index;
	}
	public void setIndex(int index) {
		this.index = index;
	}
setExpand,getLevel這兩個方法挺有意思的,主要是一種遞歸的思想 TreeHelper類是這個Tree ListView的核心思想
/**
	 * 將用戶數據轉化為Node
	 * @param datas
	 * @return
	 * @throws IllegalAccessException
	 * @throws IllegalArgumentException
	 */
	public static  List convertToNodes(List datas) throws IllegalAccessException, IllegalArgumentException{
		List nodes = new ArrayList();
		Log.i("TAG", "convertToNodes data="+datas.size()+"");
		int index = 0;
		for(T t: datas){
			Node node  =null;
			Class clazz = t.getClass();
			Field[] fileds = clazz.getDeclaredFields();
			int id =-1;
			int pid=-1;
			String label=null;
			Log.i("TAG", "fileds.length="+fileds.length);
			
			for(Field f :fileds){
				if(f.getAnnotation(TreeNodeId.class)!=null){
					f.setAccessible(true);
					id = f.getInt(t);	
					Log.i("TAG", "通過反射注解獲取到注解");
				}else{
					Log.i("TAG", "通過反射注解獲取失敗");
				}
				if(f.getAnnotation(TreeNodePid.class)!=null){
					f.setAccessible(true);
					pid = f.getInt(t);	
					Log.i("TAG", "通過反射注解獲取到注解");
				}else{
					Log.i("TAG", "通過反射注解獲取失敗");
				}
				if(f.getAnnotation(TreeNodeLabel.class)!=null){
					f.setAccessible(true);
					label = (String) f.get(t);	
					Log.i("TAG", "convertToNodes label="+label+"");
					Log.i("TAG", "通過反射注解獲取到注解");
					
				}else{
					Log.i("TAG", "通過反射注解獲取失敗");
				}
			}
			Log.i("TAG", "convertToNodes id,pid,label="+id+"-"+pid+"-"+label);
			node  = new Node(id, pid, label);
			node.setIndex(index);
			nodes.add(node);
			index++;
			
		}
	
		Log.i("TAG", "convertToNodes nodes="+nodes.size()+"");
		//關聯關系
		for(int i =0;i0&&n.isExpand()){
			n.setIcon(R.drawable.expand);
		}else if(n.getChildren().size()>0&&!n.isExpand()){
			n.setIcon(R.drawable.shrink);
			
		}else{
			n.setIcon(-1);
		}
		
	}
	public static  List getSortedNodes(List datas,int defaultExpandLevel) throws IllegalAccessException, IllegalArgumentException{
		List result = new ArrayList();
		List nodes = convertToNodes(datas);
		List rootNodes = getRootNodes(nodes);
		for(Node node : rootNodes){
			addNode(result,node,defaultExpandLevel,1);
		}
		return result;
		
	}
	private static void addNode(List result, Node node,
			int defaultExpandLevel, int curLevel) {
		node.setLevel(curLevel);
		result.add(node);
		
		if(node.isLeaf())
			return ;
		if(defaultExpandLevel>=curLevel){
			node.setExpand(true);
			
		}else{
			node.setExpand(false);
		}
		
		for(Node n:node.getChildren()){
			addNode(result, n, defaultExpandLevel, curLevel+1);
			
		}
		
	}
	/**
	 * 過濾出要顯示的
	 * @param nodes
	 * @return
	 */
	public static List filterVisbleNode(List nodes){
		List visbleNode = new ArrayList();
		for(Node n :nodes){
			if(n.isRoot()||n.isParentExpand()){
				setNodeIcon(n);
				visbleNode.add(n);
			}
		}
		return visbleNode;
		
	}
	/**
	 * 獲取根節點
	 * @param nodes
	 * @return
	 */
	private static List getRootNodes(List nodes) {
		List rootNodes = new ArrayList();
		for(Node n :nodes){
			if(n.isRoot()){
				setNodeIcon(n);
				rootNodes.add(n);
			}
		}
		return rootNodes;
	}
包含了,數據的轉化(反射和注釋准備下篇文章在闡述),數據的排序,數據的排序包括認親,遞歸獲取數據,數據 的過濾
	protected Context context;
	protected List mAllNodes;
	protected List visbleNodes;
	protected LayoutInflater inflater;
	protected ListView mTree;
	public interface OnTreeNodeClickListener{
		void onClick(Node node,int position);
	}
	private OnTreeNodeClickListener mListener;
	public void setOnTreeNodeClickListener(OnTreeNodeClickListener mClickListener){
		this.mListener =mClickListener;
		
	}
   public  TreeListViewAdapter(ListView mTree, Context context,List datas,int defaultExpandLevel) throws IllegalAccessException, IllegalArgumentException {
	// TODO Auto-generated constructor stub data
	   this.context = context;
	    mAllNodes =TreeHelper.getSortedNodes(datas, defaultExpandLevel);
	    visbleNodes = TreeHelper.filterVisbleNode(mAllNodes);
	    Log.i("TAG", "TreeListViewAdapter"+visbleNodes.size());
	    Log.i("TAG", "TreeListViewAdapter"+mAllNodes.size());
	    inflater = LayoutInflater.from(context);
	    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(visbleNodes.get(position), position);
				}
				
				
			}
		});
   }
   /**
    * 點擊收縮或展開
    * @param position
    */

	protected void expandOrCollapse(int position) {
	        Node n = visbleNodes.get(position);
	        if(n!=null){
	        	if(n.isLeaf()){
	        		return ;
	        	}
	        	n.setExpand(!n.isExpand());
	        	visbleNodes = TreeHelper.filterVisbleNode(mAllNodes);
	        	notifyDataSetChanged();
	        }
	}

	@Override
	public int getCount() {
		// TODO Auto-generated method stub
		return visbleNodes.size();
	}

	@Override
	public Object getItem(int position) {
		// TODO Auto-generated method stub
		return visbleNodes.get(position);
	}

	@Override
	public long getItemId(int position) {
		// TODO Auto-generated method stub
		return position;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		Node n = visbleNodes.get(position);
		convertView = getConvertView(visbleNodes.get(position), position, convertView, parent);
		Log.i("---------", "getView="+visbleNodes.get(position).getLabel());
		convertView.setPadding(30*n.getLevel(), 3, 3, 3);
		return convertView;
	}
	public abstract View getConvertView(Node node ,int position,View convertView,ViewGroup parent);
這是將樹形adapter封裝一次,讓外層調用者少操些ListView的心, 這三個類是樹形ListView的核心類,在項目結構上看到的最後三個類是注釋類,自己bean必須加上注釋才能便於我解析,否則就無法解析,就不能正常轉換數據。  
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved