android 树形目录结构的实现(包含源码)
生活随笔
收集整理的這篇文章主要介紹了
android 树形目录结构的实现(包含源码)
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
1.效果如圖 ,老板的需求:
1.各種群按照樹形目錄展開
2.點(diǎn)擊列表可以收縮展開
3.選中后進(jìn)行篩選
2.分析下思路
2.為避免多重嵌套影響性能,這里的數(shù)據(jù)展示我們用一個列表足矣實(shí)現(xiàn)
3.實(shí)現(xiàn)的思路是item向右偏移
3.貼代碼時間
Node節(jié)點(diǎn)對象的定義 項(xiàng)目中用到了環(huán)信SDK 環(huán)信部分直接忽略吧 QAQ
import java.io.Serializable; import java.util.ArrayList; import java.util.List;public class Node implements Serializable{/*** 節(jié)點(diǎn)id*/private int id;/*** 父節(jié)點(diǎn)id*/private int pId;/*** 是否展開*/private boolean isExpand = false;private boolean isChecked = false;private boolean isHideChecked = true;/*** 節(jié)點(diǎn)名字*/private String name;/*** 節(jié)點(diǎn)級別*/private int level;/*** 節(jié)點(diǎn)展示圖標(biāo)*/private int icon;/*** 節(jié)點(diǎn)所含的子節(jié)點(diǎn)*/private List<Node> childrenNodes = new ArrayList<Node>();/*** 節(jié)點(diǎn)的父節(jié)點(diǎn)*/private Node parent;/*** 環(huán)信群ID*/private String hxGroupId;public Node() {}public Node(int id, int pId, String name,String hxGroupId) {super();this.id = id;this.pId = pId;this.name = name;this.hxGroupId = hxGroupId;}public String getHxGroupId() {return hxGroupId;}public void setHxGroupId(String hxGroupId) {this.hxGroupId = hxGroupId;}@Overridepublic String toString() {return "Node{" +"id=" + id +", pId=" + pId +", isExpand=" + isExpand +", isChecked=" + isChecked +", isHideChecked=" + isHideChecked +", name='" + name + '\'' +", level=" + level +", icon=" + icon +", childrenNodes=" + childrenNodes +", parent=" + parent +", hxGroupId='" + hxGroupId + '\'' +'}';}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 boolean isExpand() {return isExpand;}/*** 當(dāng)父節(jié)點(diǎn)收起,其子節(jié)點(diǎn)也收起* @param isExpand*/public void setExpand(boolean isExpand) {this.isExpand = isExpand;if (!isExpand) {for (Node node : childrenNodes) {node.setExpand(isExpand);}}}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getLevel() {return parent == null ? 0 : parent.getLevel() + 1;}public void setLevel(int level) {this.level = level;}public int getIcon() {return icon;}public void setIcon(int icon) {this.icon = icon;}public List<Node> getChildrenNodes() {return childrenNodes;}public void setChildrenNodes(List<Node> childrenNodes) {this.childrenNodes = childrenNodes;}public Node getParent() {return parent;}public void setParent(Node parent) {this.parent = parent;}/*** 判斷是否是根節(jié)點(diǎn)* * @return*/public boolean isRoot() {return parent == null;}/*** 判斷是否是葉子節(jié)點(diǎn)* * @return*/public boolean isLeaf() {return childrenNodes.size() == 0;}/*** 判斷父節(jié)點(diǎn)是否展開* * @return*/public boolean isParentExpand(){if (parent == null)return false;return parent.isExpand();}public boolean isChecked() {return isChecked;}public void setChecked(boolean isChecked) {this.isChecked = isChecked;}public boolean isHideChecked() {return isHideChecked;}public void setHideChecked(boolean isHideChecked) {this.isHideChecked = isHideChecked;} }幫助類TreeHelper
import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List;public class TreeHelper {/*** 根據(jù)所有節(jié)點(diǎn)獲取可見節(jié)點(diǎn)* * @param allNodes* @return*/public static List<Node> filterVisibleNode(List<Node> allNodes) {List<Node> visibleNodes = new ArrayList<Node>();for (Node node : allNodes) {// 如果為根節(jié)點(diǎn),或者上層目錄為展開狀態(tài)if (node.isRoot() || node.isParentExpand()) {setNodeIcon(node);visibleNodes.add(node);}}return visibleNodes;}/*** 獲取排序的所有節(jié)點(diǎn)* * @param datas* @param defaultExpandLevel* @return* @throws IllegalArgumentException* @throws IllegalAccessException*/public static <T> List<Node> getSortedNodes(List<T> datas,int defaultExpandLevel, boolean isHide)throws IllegalAccessException, IllegalArgumentException {List<Node> sortedNodes = new ArrayList<Node>();// 將用戶數(shù)據(jù)轉(zhuǎn)化為List<Node>List<Node> nodes = convertData2Nodes(datas, isHide);// 拿到根節(jié)點(diǎn)List<Node> rootNodes = getRootNodes(nodes);// 排序以及設(shè)置Node間關(guān)系for (Node node : rootNodes) {addNode(sortedNodes, node, defaultExpandLevel, 1);}return sortedNodes;}/*** 把一個節(jié)點(diǎn)上的所有的內(nèi)容都掛上去*/private static void addNode(List<Node> nodes, Node node,int defaultExpandLeval, int currentLevel) {nodes.add(node);if (defaultExpandLeval >= currentLevel) {node.setExpand(true);}if (node.isLeaf())return;for (int i = 0; i < node.getChildrenNodes().size(); i++) {addNode(nodes, node.getChildrenNodes().get(i), defaultExpandLeval,currentLevel + 1);}}/*** 獲取所有的根節(jié)點(diǎn)* * @param nodes* @return*/public static List<Node> getRootNodes(List<Node> nodes) {List<Node> rootNodes = new ArrayList<Node>();for (Node node : nodes) {if (node.isRoot()) {rootNodes.add(node);}}return rootNodes;}/*** 將泛型datas轉(zhuǎn)換為node* * @param datas* @return* @throws IllegalArgumentException* @throws IllegalAccessException*/public static <T> List<Node> convertData2Nodes(List<T> datas, boolean isHide)throws IllegalAccessException, IllegalArgumentException {List<Node> nodes = new ArrayList<Node>();Node node = null;for (T t : datas) {int id = -1;int pId = -1;String name = null;String hxGroupId = null;Class<? extends Object> clazz = t.getClass();Field[] declaredFields = clazz.getDeclaredFields();/*** 與MyNodeBean實(shí)體一一對應(yīng)*/for (Field f : declaredFields) {if ("id".equals(f.getName())) {f.setAccessible(true);id = f.getInt(t);}if ("pId".equals(f.getName())) {f.setAccessible(true);pId = f.getInt(t);}if ("name".equals(f.getName())) {f.setAccessible(true);name = (String) f.get(t);}if ("hxGroupId".equals(f.getName())) {f.setAccessible(true);hxGroupId = (String) f.get(t);}if ("desc".equals(f.getName())) {continue;}if ("length".equals(f.getName())) {continue;}if (id == -1 && pId == -1 && name == null&&hxGroupId==null) {break;}}node = new Node(id, pId, name,hxGroupId);node.setHideChecked(isHide);nodes.add(node);}/*** 比較nodes中的所有節(jié)點(diǎn),分別添加children和parent*/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 (n.getId() == m.getpId()) {n.getChildrenNodes().add(m);m.setParent(n);} else if (n.getpId() == m.getId()) {n.setParent(m);m.getChildrenNodes().add(n);}}}for (Node n : nodes) {setNodeIcon(n);}return nodes;}/*** 設(shè)置打開,關(guān)閉icon* * @param node*/public static void setNodeIcon(Node node) {if (node.getChildrenNodes().size() > 0 && node.isExpand()) {node.setIcon(R.drawable.arrow_right);} else if (node.getChildrenNodes().size() > 0 && !node.isExpand()) {node.setIcon(R.drawable.arrow_down);} elsenode.setIcon(-1);}public static void setNodeChecked(Node node, boolean isChecked) {// 自己設(shè)置是否選擇node.setChecked(isChecked);/*** 非葉子節(jié)點(diǎn),子節(jié)點(diǎn)處理*/setChildrenNodeChecked(node, isChecked);/** 父節(jié)點(diǎn)處理 */setParentNodeChecked(node);}/*** 非葉子節(jié)點(diǎn),子節(jié)點(diǎn)處理*/private static void setChildrenNodeChecked(Node node, boolean isChecked) {node.setChecked(isChecked);if (!node.isLeaf()) {for (Node n : node.getChildrenNodes()) {// 所有子節(jié)點(diǎn)設(shè)置是否選擇setChildrenNodeChecked(n, isChecked);}}}/*** 設(shè)置父節(jié)點(diǎn)選擇* * @param node*/private static void setParentNodeChecked(Node node) {/** 非根節(jié)點(diǎn) */if (!node.isRoot()) {Node rootNode = node.getParent();boolean isAllChecked = true;for (Node n : rootNode.getChildrenNodes()) {if (!n.isChecked()) {isAllChecked = false;break;}}if (isAllChecked) {rootNode.setChecked(true);} else {rootNode.setChecked(false);}setParentNodeChecked(rootNode);}}}適配器TreeListViewAdapter
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.CheckBox; import android.widget.CompoundButton; import android.widget.CompoundButton.OnCheckedChangeListener; import android.widget.ListView; import android.widget.RelativeLayout;import java.util.ArrayList; import java.util.List;/*** tree適配器* @param <T>*/ public abstract class TreeListViewAdapter<T> extends BaseAdapter {protected Context mContext;/*** 存儲所有可見的Node*/protected List<Node> mNodes;protected LayoutInflater mInflater;/*** 存儲所有的Node*/protected List<Node> mAllNodes;/*** 點(diǎn)擊的回調(diào)接口*/private OnTreeNodeClickListener onTreeNodeClickListener;public interface OnTreeNodeClickListener {/*** 處理node click事件* @param node* @param position*/void onClick(Node node, int position);/*** 處理checkbox選擇改變事件* @param node* @param position* @param checkedNodes*/void onCheckChange(Node node, int position, List<Node> checkedNodes);}public void setOnTreeNodeClickListener(OnTreeNodeClickListener onTreeNodeClickListener) {this.onTreeNodeClickListener = onTreeNodeClickListener;}/*** * @param mTree* @param context* @param datas* @param defaultExpandLevel* 默認(rèn)展開幾級樹* @throws IllegalArgumentException* @throws IllegalAccessException*/public TreeListViewAdapter(ListView mTree, Context context, List<T> datas,int defaultExpandLevel, boolean isHide)throws IllegalArgumentException, IllegalAccessException {mContext = context;/*** 對所有的Node進(jìn)行排序*/mAllNodes = TreeHelper.getSortedNodes(datas, defaultExpandLevel, isHide);/*** 過濾出可見的Node*/mNodes = TreeHelper.filterVisibleNode(mAllNodes);mInflater = LayoutInflater.from(context);/*** 設(shè)置節(jié)點(diǎn)點(diǎn)擊時,可以展開以及關(guān)閉;并且將ItemClick事件繼續(xù)往外公布*/mTree.setOnItemClickListener(new OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> parent, View view,int position, long id) {expandOrCollapse(position);if (onTreeNodeClickListener != null) {onTreeNodeClickListener.onClick(mNodes.get(position),position);}}});}/*** 相應(yīng)ListView的點(diǎn)擊事件 展開或關(guān)閉某節(jié)點(diǎn)* * @param position*/public void expandOrCollapse(int position) {Node n = mNodes.get(position);if (n != null)// 排除傳入?yún)?shù)錯誤異常{if (!n.isLeaf()) {n.setExpand(!n.isExpand());mNodes = TreeHelper.filterVisibleNode(mAllNodes);notifyDataSetChanged();// 刷新視圖}}}@Overridepublic int getCount() {return mNodes.size();}@Overridepublic Object getItem(int position) {return mNodes.get(position);}@Overridepublic long getItemId(int position) {return position;}@Overridepublic View getView(final int position, View convertView, ViewGroup parent) {final Node node = mNodes.get(position);convertView = getConvertView(node, position, convertView, parent);// 設(shè)置內(nèi)邊距convertView.setPadding(node.getLevel() * 56, 3, 3, 3);if (!node.isHideChecked()) {//獲取各個節(jié)點(diǎn)所在的父布局RelativeLayout myView = (RelativeLayout) convertView;//父布局下的CheckBoxCheckBox cb = (CheckBox) myView.getChildAt(0);//擴(kuò)充可觸摸的區(qū)域//expandViewTouchDelegate(cb,50,50,50,50);cb.setOnCheckedChangeListener(new OnCheckedChangeListener(){@Overridepublic void onCheckedChanged(CompoundButton buttonView,boolean isChecked) {TreeHelper.setNodeChecked(node, isChecked);List<Node> checkedNodes = new ArrayList<Node>();for(Node n:mAllNodes){if(n.isChecked()){checkedNodes.add(n);}}onTreeNodeClickListener.onCheckChange(node,position,checkedNodes);TreeListViewAdapter.this.notifyDataSetChanged();}});}return convertView;}public abstract View getConvertView(Node node, int position,View convertView, ViewGroup parent);/*** 更新* @param isHide*/public void updateView(boolean isHide){for(Node node:mAllNodes){node.setHideChecked(isHide);}this.notifyDataSetChanged();}activity中的主要代碼
private void initView() {initTreeData();try {adapter = new MyTreeListViewAdapter<>(treeLv, this,mDatas, 0, isHide);adapter.setOnTreeNodeClickListener(new TreeListViewAdapter.OnTreeNodeClickListener() {@Overridepublic void onClick(Node node, int position) {if (node.isLeaf()) {}}@Overridepublic void onCheckChange(Node node, int position,List<Node> checkedNodes) {// TODO Auto-generated method stubcheckedNode = checkedNodes;StringBuffer sb = new StringBuffer();for (Node n : checkedNodes) {sb.append(n.getName()).append(":").append(n.getHxGroupId());}Logger.d("選中的" + sb.toString());}});adapter.updateView(isHide);} catch (IllegalArgumentException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IllegalAccessException e) {// TODO Auto-generated catch blocke.printStackTrace();}treeLv.setAdapter(adapter);}private void initTreeData() {for (ChatGroupEntity.RDataBean bean : countTask.getRData()) {mDatas.add(new MyNodeBean(Integer.valueOf(bean.getGroup_id()), Integer.valueOf(bean.getUp_group_id()), bean.getGroup_code(), bean.getHx_id()));}}布局代碼
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="match_parent"android:focusable="true"android:focusableInTouchMode="true"android:layout_height="match_parent"><include layout="@layout/title_bar_common"/><com.fjrcloud.fuqing.util.customview.ClearEditText android:id="@+id/filter_edit"android:layout_width="match_parent"android:layout_height="30dp"android:focusableInTouchMode="true"android:layout_marginTop="8dip"android:layout_marginLeft="15dp"android:layout_marginRight="15dp"android:gravity="center_vertical"android:layout_marginBottom="8dp"android:paddingLeft="15dp"android:drawablePadding="15dp"android:background="@drawable/shape_search_view"android:drawableLeft="@mipmap/icon_check_name"android:hint="搜索"android:singleLine="true"android:textSize="14sp"/><TextView android:background="#f1f1f1"android:layout_width="match_parent"android:layout_height="@dimen/dp_15"/><ListView android:layout_marginTop="15dp"android:id="@+id/tree_lv"android:layout_width="match_parent"android:layout_height="match_parent"></ListView></LinearLayout>OK收工。有什么不懂得可以留言 聯(lián)系我QQ :910689331
或者微博:Liberation_k
當(dāng)然 源碼在這哈
鏈接:http://pan.baidu.com/s/1c0KpS6 密碼:q4xf
總結(jié)
以上是生活随笔為你收集整理的android 树形目录结构的实现(包含源码)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 关税靴子落地,债市反应强烈,2只30年国
- 下一篇: Flyme6系统适配教程(Patchro