首页 > 代码库 > android ListView 实现3级节点 (可拓展N级)

android ListView 实现3级节点 (可拓展N级)

            ListView实现二级节点想必大家都知道可以用ExpandableListView 就可以轻松实现,但是要实现3级甚至多级菜单怎么实现呢? 再利用ExpandableListView 就会十分繁琐,今天我们来探究另一种实现方式来实现。

          思路:每次点击展开子菜单 ,可以理解为 listView的一次重绘(数据更新<增加子节点数据>),而收起子菜单就是移除当前节点下的子数据,这是数据更新。对于界面每一个itemView的实现可以在adapter里面实现,根据没个子元素的级别,是否含有子节点,是否已经展开来配置不同的界面显示效果。首先来看实现的效果:

技术分享技术分享


技术分享

1:首先看子元素bean

package com.example.androidexpandablelistview;

import java.util.ArrayList;
import java.util.List;
/**
 * 元素 可根据需要添加新的属性 
 * @author jrh
 *
 */
public class TreeElement {
	/**
	 * 各个元素的层级标识
	 */
	private int parentLevel;
	/**
	 * 节点显示标题
	 */
	private String noteName;
	/**
	 * 子节点元素集合
	 */
	private ArrayList<TreeElement> dataList = new ArrayList<TreeElement>();
	/**
	 * 是否已扩展
	 */
	private boolean isExpandAble;
	/**
	 * 是否有子节点元素
	 */
	private boolean isHasChild;
	/**
	 * 当前节点位置
	 */
	private int position;

	/**
	 * 
	 * @param parentLevel 各个元素的层级标识
	 * @param noteName 节点显示标题
	 * @param dataList 子节点元素集合
	 * @param isExpandAble 是否已扩展
	 * @param isHasChild 是否有子节点元素
	 * @param position 当前节点位置
	 */

	public TreeElement(int parentLevel, String noteName,
			ArrayList<TreeElement> dataList, boolean isExpandAble,
			boolean isHasChild, int position) {
		super();
		this.parentLevel = parentLevel;
		this.noteName = noteName;
		this.dataList = dataList;
		this.isExpandAble = isExpandAble;
		this.isHasChild = isHasChild;
		this.position = position;
	}

	public int getPosition() {
		return position;
	}

	public void setPosition(int position) {
		this.position = position;
	}

	public boolean isHasChild() {
		return isHasChild;
	}

	public void setHasChild(boolean isHasChild) {
		this.isHasChild = isHasChild;
	}



	public int getParentLevel() {
		return parentLevel;
	}

	public void setParentLevel(int parentLevel) {
		this.parentLevel = parentLevel;
	}

	public String getNoteName() {
		return noteName;
	}

	public void setNoteName(String noteName) {
		this.noteName = noteName;
	}


	public ArrayList<TreeElement> getDataList() {
		return dataList;
	}

	public void setDataList(ArrayList<TreeElement> dataList) {
		this.dataList = dataList;
	}

	public boolean isExpandAble() {
		return isExpandAble;
	}

	public void setExpandAble(boolean isExpandAble) {
		this.isExpandAble = isExpandAble;
	}



}

2:数据更新adapter


package com.example.androidexpandablelistview;

import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
/**
 * 处理点击 数据更新 通用
 * @author jrh
 *
 */
public class TreeAdapter extends BaseAdapter {

	private List<TreeElement> mParentList;
	private Context context;

	public TreeAdapter(List<TreeElement> parentList, Context context) {
		super();
		this.mParentList = parentList;
		this.context = context;
	}

	@Override
	public int getCount() {
		// TODO Auto-generated method stub
		return mParentList == null ? 0 : mParentList.size();
	}

	@Override
	public Object getItem(int arg0) {
		// TODO Auto-generated method stub
		return mParentList == null ? null : mParentList.get(arg0);
	}

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

	@Override
	public View getView(int arg0, View arg1, ViewGroup arg2) {
		// TODO Auto-generated method stub
		return null;
	}

	public void onExpandClick(int position) {
		// 父节点没有子元素直接返回
		if (!mParentList.get(position).isHasChild()) {
			return;
		}
		// 父节点已经扩展
		if (mParentList.get(position).isExpandAble()) {
			mParentList.get(position).setExpandAble(false);
			TreeElement element = mParentList.get(position);
			// 遍历已扩展的元素,删除
			ArrayList<TreeElement> temp = new ArrayList<TreeElement>();
			// 从当前点的下一个元素开始隐藏
			for (int i = position + 1; i < mParentList.size(); i++) {

				if (element.getParentLevel() >= mParentList.get(i)
						.getParentLevel()) {
					break;
				}
				temp.add(mParentList.get(i));
			}

			mParentList.removeAll(temp);

			for (int i = position + 1; i < mParentList.size(); i++) {
				mParentList.get(i).setPosition(i);
			}
			
			notifyDataSetChanged();
		} else {
			// 父节点为点开

			TreeElement objElement = mParentList.get(position);
			objElement.setExpandAble(true);
			int level = objElement.getParentLevel();
			int nextLevel = level + 1;

			ArrayList<TreeElement> tempList = objElement.getDataList();
			//扩充父类集合
			for (int i = 0; i < tempList.size(); i++) {
				TreeElement element = tempList.get(i);
				element.setParentLevel(nextLevel);
				element.setExpandAble(false);
				mParentList.add(position+1,element);
			}
			
			for (int i = position+1; i <mParentList.size(); i++) {
				mParentList.get(i).setPosition(i);
			}
			
			notifyDataSetChanged();
			
		}

	}

}

3:具体适配adapter


package com.example.androidexpandablelistview;

import java.util.List;

import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.LayerDrawable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
/**
 * 具体子adapter 可根据不同的要求自定义
 * @author jrh
 *
 */
public class DetaiTreeAdapter extends TreeAdapter {

	private LayoutInflater inflater;
	private List<TreeElement> mParentList;

	public DetaiTreeAdapter(List<TreeElement> parentList, Context context) {
		super(parentList, context);
		inflater = LayoutInflater.from(context);
		mParentList = parentList;
	}

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

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

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

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		// TODO Auto-generated method stub

		// hodler 需为局部变量
		ViewHodler hodler = new ViewHodler();
		TreeElement treeElement = mParentList.get(position);
		if (convertView == null) {
			convertView = inflater.inflate(R.layout.itemview, null);
			hodler.icon = (ImageView) convertView.findViewById(R.id.ic_img);
			hodler.title = (TextView) convertView.findViewById(R.id.title_tv);
			hodler.connection = (RelativeLayout) convertView
					.findViewById(R.id.layout_treeview_connection);

			convertView.setTag(hodler);

		} else {
			hodler = (ViewHodler) convertView.getTag();
		}
		// "-"; "+";图标处理
		if (treeElement.isHasChild()) {
			if (treeElement.isExpandAble()) {
				if (treeElement.getParentLevel() == 0) {
					hodler.icon
							.setImageResource(R.drawable.knowledgetree_rootexpanded);
				} else {
					hodler.icon
							.setImageResource(R.drawable.knowledgetree_expanded);
				}
			} else {
				if (treeElement.getParentLevel() == 0) {
					hodler.icon
							.setImageResource(R.drawable.knowledgetree_rootunexpanded);
				} else {
					hodler.icon
							.setImageResource(R.drawable.knowledgetree_unexpanded);
				}
			}
		} else {
			hodler.icon.setImageResource(R.drawable.knowledgetree_leaf);
		}
		// 设置 展开 时,“-”、“+”间的连线
		if (treeElement.getParentLevel() == 0) {
			if (position + 1 < getCount()
					&& mParentList.get(position + 1).getParentLevel() == 0) {
				hodler.connection.setBackgroundResource(0);
			} else if (position + 1 == getCount()) {
				hodler.connection.setBackgroundResource(0);
			} else {
				hodler.connection
						.setBackgroundResource(R.drawable.knowledgetree_halfconnection_root);

			}
		} else {
			if (position + 1 < getCount()
					&& mParentList.get(position + 1).getParentLevel() == 0) {
				hodler.connection
						.setBackgroundResource(R.drawable.knowledgetree_halfconnection_leaf);
			} else if (position == getCount() - 1)
				hodler.connection
						.setBackgroundResource(R.drawable.knowledgetree_halfconnection_leaf);
			else
				hodler.connection
						.setBackgroundResource(R.drawable.knowledgetree_connection);
		}
		// 标题背景设置
		if (treeElement.getParentLevel() == 0) {
			hodler.title.setBackgroundColor(Color.BLUE);
			hodler.title.setPadding(8, 8, 8, 8);
		} else if (treeElement.getParentLevel() == 1) {
			hodler.title.setBackgroundColor(Color.RED);
			hodler.title.setPadding(38, 8, 8, 8);
		} else if (treeElement.getParentLevel() == 2) {
			hodler.title.setPadding(78, 8, 8, 8);
			hodler.title.setBackgroundColor(Color.GRAY);
		}
		hodler.title.setTextColor(Color.WHITE);
		hodler.title.setText(treeElement.getNoteName());

		return convertView;

	}

	@Override
	public void onExpandClick(int position) {
		super.onExpandClick(position);
	}

	class ViewHodler {
		ImageView icon;
		TextView title;
		RelativeLayout connection;

	}

}

4:主界面


package com.example.androidexpandablelistview;

import java.util.ArrayList;

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.view.Window;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;

public class MainActivity extends Activity {

	private ListView mLv;
	private DetaiTreeAdapter adapter;
	private ArrayList<TreeElement> dataList;
	private ArrayList<TreeElement> seconddataList;
	private ArrayList<TreeElement> thirddataList;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		setContentView(R.layout.activity_main);
		initView();
		initData();
		initEvent();
	}

	/**
	 * 事件处理
	 */
	private void initEvent() {
		mLv.setOnItemClickListener(new OnItemClickListener() {

			@Override
			public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
					long arg3) {
				adapter.onExpandClick(arg2);
			}
		});

	}

	/**
	 * 数据加载
	 */
	private void initData() {
		dataList  = new ArrayList<TreeElement>();
		seconddataList = new ArrayList<TreeElement>();
		thirddataList = new ArrayList<TreeElement>();
		adapter = new DetaiTreeAdapter(dataList, MainActivity.this);
		mLv.setAdapter(adapter);
		//模拟三级节点数据
		for (int i = Data.thridTitle.length-1; i >=0; i--) {
			TreeElement element = new TreeElement(2, Data.thridTitle[i], new ArrayList<TreeElement>(),
					false, false, i);
			thirddataList.add(element);
		}
		//模拟二级节点数据
		for (int i = Data.secondTitle.length-1; i >=0; i--) {
			TreeElement element = new TreeElement(1, Data.secondTitle[i],
					i == 0 ? thirddataList : null, false,
					i == 0 ? true : false, i);
			seconddataList.add(element);
		}
		//模拟一级节点数据
		for (int i = 0; i < Data.title.length; i++) {
			TreeElement element = new TreeElement(0, Data.title[i],
					
					i == 0 ? seconddataList : null, false, i == 0 ? true
							: false, i);
			dataList.add(element);
		}
		adapter.notifyDataSetChanged();
	}

	private void initView() {
		mLv = (ListView) findViewById(R.id.lv);

	}

}

5:模拟数据

package com.example.androidexpandablelistview;
/**
 * 模拟数据
 * @author jrh
 *
 */
public class Data {
	public static String title[] = {"常识判断","言语理解","数量关系","判断推理","资料分析"};
	public static String secondTitle[]={"政治","经济","法律","历史","人文"};
	public static String thridTitle[] ={"时政","马克思主义哲学","中共党史","中国特色社会主义体系"};

}

6:界面布局

<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"
 >

    <ListView
        android:id="@+id/lv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
         />

</RelativeLayout>

7:itemView

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center|left"
    android:orientation="horizontal"
    android:paddingLeft="8dp" >

    <RelativeLayout
        android:layout_width="wrap_content"
        android:layout_height="fill_parent" >

        <RelativeLayout
            android:id="@+id/layout_treeview_connection"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            >

            <ImageView
                android:id="@+id/img_treeview_ico"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_centerInParent="true"
                android:scaleType="fitXY"
                android:contentDescription="@string/app_name" />
        </RelativeLayout>

        <ImageView
            android:id="@+id/ic_img"
              android:layout_centerInParent="true"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
           />
    </RelativeLayout>

    <TextView
        android:id="@+id/title_tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="8dp"
        android:textSize="18sp" />

</LinearLayout>




示例代码下载




















android ListView 实现3级节点 (可拓展N级)