博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android - N级树形结构实现
阅读量:5215 次
发布时间:2019-06-14

本文共 19479 字,大约阅读时间需要 64 分钟。

    目前已经实现3级之内的任意级树形结构展示(如果想增加更多级,需要扩展排序算法),并支持单选和多选(使用不同的适配器)。

    实现使用的控件:ListView

    首先,最重要的应该是数据源的格式,支持树形结构的数据源,每条数据应该都要指明它的父级是谁,本文为parent_org,并把每条数据都存放在一个HashMap里面。这里使用的除了parent_org(父营业部),还有org_name(营业部名称),org_code(营业部编号)。

    其次,对数据进行排序。因为只使用ListView实现,所以需要实现层次结构的树形结构,需要对数据按父级->2级->3级->父级->2级->父级->2级->父级->2级->3级这样的顺序排序。

    接着,实现适配器,展现树形结构。

    最后,调用适配器,并调用适配器里的方法获取选择结果。

排序算法:

 

/** * 查询操作员营业部列表类 *  * @author xinyan *  */public class QueryIntOrgListWork extends BaseWork implements Runnable {	private static final String TAG = "QueryIntOrgListWork";	HashMap
params; public QueryIntOrgListWork(Context context, Map args) { super(context, args); } public QueryIntOrgListWork(Context context, View layoutView, Map args) { super(context, layoutView, args); } @Override public void work() { params = new HashMap
(); AppState appState = AppState.getState(); BrokerInfo brokerInfo = appState.getBrokerInfo(); // params.put("uuid", brokerInfo.getUuid()); Utils.putUuid(params); params.put("funcno", "20017"); params.put("org_type", "0"); params.put("right_flag", "1"); try { HttpFactory httpFactory = new HttpFactory(); byte[] bytes = httpFactory.send( Configuration.getString("system.http"), params, HttpFactory.POST); if (bytes == null) { return; } String result = new String(bytes, Configuration.getString("system.charSet")); JSONObject jsonObject = new JSONObject(result); // 增加登录过期或账号已在其他地方登录的处理 try { String strPrompt = jsonObject.getString("errorInfo"); String strErrorNo = jsonObject.getString("errorNo"); if (!StringHelper.isEmpty(strPrompt)) { if (strPrompt.contains("未登") || strPrompt.contains("其它地方登陆")) { sendMessage(new LoginExpiredUiWork(null)); return; } } // 如果访问接口异常,提示信息 if (!strErrorNo.equals("0")) { HashMap
param = new HashMap
(); if (null != strPrompt) { param.put("errorInfo", "调用查询操作员机构列表接口:" + strPrompt); } else { param.put("errorInfo", ""); } sendMessage(new CallInterfaceExceptionUiWork(param)); if ("-111".equals(strErrorNo) || "-110".equals(strErrorNo) || "-2008000".equals(strErrorNo)) { return; } } } catch (Exception e) { } String errorNo = jsonObject.getString("errorNo"); if (errorNo.equals("-1")) { String errorInfo = jsonObject.getString("errorInfo"); Map
map = new HashMap
(); map.put("errorNo", "-1"); map.put("errorInfo", errorInfo); } else if (errorNo.equals("-999")) { Intent intent = new Intent("com.thinkive.action.MAIN"); context.startActivity(intent); } else if (errorNo.equals("0")) { JSONArray array = jsonObject.getJSONArray("results"); ArrayList
> dataList = new ArrayList
>(); HashMap
dataItem = null; for (int i = 0; i < array.length(); i++) { dataItem = new HashMap
(); JSONObject item = array.getJSONObject(i); String org_name = item.getString("org_name"); // String area_addr = item.getString("area_addr"); // // String org_type = item.getString("org_type"); // String right_flag = item.getString("right_flag"); // String zip_code = item.getString("zip_code"); // String acct_len = item.getString("acct_len"); String org_code = item.getString("org_code"); // String acct_prefix = item.getString("acct_prefix"); // String org_full_name = item.getString("org_full_name"); String parent_org = item.getString("parent_org"); // String area_no = item.getString("area_no"); // String org_status = item.getString("org_status"); // String org_cls = item.getString("org_cls"); dataItem.put("org_name", org_name); dataItem.put("org_code", org_code); dataItem.put("parent_org", parent_org); dataList.add(dataItem); } AppState.getState().getBrokerInfo() .setIntOrgs(regroupData(dataList)); } } catch (Exception e) { e.printStackTrace(); } } /** * 对数据根据子父级关系进行重组 */ private List
> regroupData( List
> dataList) { HashMap
item = null; ArrayList
> regroupedDataList = null; for (int i = 0; i < dataList.size(); i++) { item = dataList.get(i); String strOrg = item.get("org_code").toString(); String strParentOrg = item.containsKey("parent_org") ? item.get( "parent_org").toString() : ""; // 如果没有父营业部,遍历列表是否存在子营业部 if (StringHelper.isEmpty(strParentOrg)) { HashMap
item2 = null; ArrayList
> childList = null; // 遍历列表是否存在子营业部 for (int j = 0; j < dataList.size(); j++) { if (i == j) { continue; } item2 = dataList.get(j); // 列表存在子营业部 if (strOrg.equals(item2.get("parent_org"))) { childList = new ArrayList
>(); if (null != item2.get("child")) { // 如果该营业部的子营业部还存在子营业部,那么此营业部是1级,最高级 item2.put("org_level", "1"); } else { // 如果该营业部的子营业部不存在子营业部,那么将此营业部暂定为2级 item2.put("org_level", "2"); } childList.add(item2); }// end if }// end for item.put("child", childList); } else {// 如果有父营业部 HashMap
parentOrgItem = null; boolean isParentOrgExist = false; // 首先检查列表是否存在父营业部 for (int j = 0; j < dataList.size(); j++) { if (i == j) { continue; } parentOrgItem = dataList.get(j); // 列表存在父营业部 if (strParentOrg.equals(parentOrgItem.get("org_code"))) { isParentOrgExist = true; // 加入当前营业部到该父营业部的子营业部列表,标记当前项为2级营业部 item.put("org_level", "2"); ArrayList
> childList = null; if (null != parentOrgItem.get("child")) { childList = (ArrayList
>) parentOrgItem .get("child"); } else { childList = new ArrayList
>(); } // 检查子营业部列表是否已经存在该营业部 boolean isOrgExist = false; if (childList.size() > 0) { HashMap
childItem = null; for (int k = 0; k < childList.size(); k++) { childItem = (HashMap
) childList .get(k); if (childItem.get("org_code").toString() .equals(item.get("org_code"))) { isOrgExist = true; } } } if (!isOrgExist) { childList.add(item); parentOrgItem.put("child", childList); } break; }// end if }// end for // 检查完了是否存在父营业部之后,再检查列表是否存在该营业部的子营业部 HashMap
childOrgItem = null; ArrayList
> childList = new ArrayList
>(); // 遍历列表是否存在子营业部 for (int k = 0; k < dataList.size(); k++) { if (i == k) { continue; } childOrgItem = dataList.get(k); // 列表存在子营业部 if (strOrg.equals(childOrgItem.get("parent_org"))) { if (null != childOrgItem.get("child")) { // 如果该营业部的子营业部还存在子营业部,那么此营业部是1级,最高级 childOrgItem.put("org_level", "1"); } else { // 如果该营业部的子营业部不存在子营业部,那么将此营业部暂定为2级 childOrgItem.put("org_level", "2"); } childList.add(childOrgItem); }// end if }// end for if (childList.size() > 0) { item.put("child", childList); // 如果当前营业部存在父营业部和子营业部,那么就是2级 if (isParentOrgExist) { item.put("org_level", "2"); } else { // 不存在父营业部,那么是1级 item.put("org_level", "1"); } } else { // 不存在子营业部 if (isParentOrgExist) { // 不存在子营业部,但存在父营业部,那么是2级 item.put("org_level", "2"); } else { // 不存在子营业部和父营业部,那么是1级 item.put("org_level", "1"); } } }// end else }// end for // 当数据按数学结构组织好之后,按顺序排列为列表,以便在listview里显示 regroupedDataList = new ArrayList
>(); HashMap
tempItem = null; for (int i = 0; i < dataList.size(); i++) { tempItem = dataList.get(i); if ("1".equals(tempItem.get("org_level").toString())) { regroupedDataList.add(tempItem); // 把子营业部加入到重组后的列表 if (tempItem.containsKey("child")) { ArrayList
> childList = (ArrayList
>) tempItem .get("child"); HashMap
childItem = null; if (childList.size() > 0) { for (int j = 0; j < childList.size(); j++) { childItem = (HashMap
) childList .get(j); regroupedDataList.add(childItem); // 检查子营业部是否还有子营业部 if (childItem.containsKey("child")) { ArrayList
> childList2 = (ArrayList
>) childItem .get("child"); HashMap
childItem2 = null; if (childList2.size() > 0) { for (int k = 0; k < childList2.size(); k++) { childItem2 = (HashMap
) childList2 .get(k); regroupedDataList.add(childItem2); }// end for }// end if }// end if }// end for }// end if }// end if }// end if }// end for for (int i = 0; i < regroupedDataList.size(); i++) { if (regroupedDataList.get(i).containsKey("child")) { regroupedDataList.get(i).remove("child"); } } // 父级、子级都得排序 Log.i(TAG, "重组前的营业部数据" + dataList); Log.i(TAG, "重组后的营业部数据" + regroupedDataList); return regroupedDataList; } @Override public void run() { work(); }}

 

 

多选营业部树形列表适配器:

 

 

 

/** * 多选营业部树形列表适配器 *  * @author xinyan * @date 2013-5-27 */public class MultiCheckIntOrgListAdapter extends BaseAdapter {	public static final String TAG = "MultiCheckIntOrgListAdapter";	public static final String CHECKED_TRUE = "1";	public static final String CHECKED_FALSE = "0";	public static final String IS_CHECKED = "IS_CHECKED";	private List
> mDataList; private LayoutInflater mInflater; public MultiCheckIntOrgListAdapter(Context context, List
> dataList) { this.mInflater = LayoutInflater.from(context); mDataList = dataList; setDefaultChecked(); } @Override public int getCount() { return mDataList.size(); } @Override public Object getItem(int position) { return mDataList.get(position); } @Override public long getItemId(int position) { return 0; } @Override public View getView(final int position, View convertView, ViewGroup parent) { ViewHolder holder = null; final HashMap
dataItem = mDataList.get(position); if (null == convertView) { holder = new ViewHolder(); convertView = mInflater.inflate(R.layout.lv_item_tree_structure, null); holder.cb = (CheckBox) convertView .findViewById(R.id.lv_item_tree_structure_cb); holder.text = (TextView) convertView .findViewById(R.id.lv_item_tree_structure_text); holder.joinBottom = (ImageView) convertView .findViewById(R.id.lv_item_tree_structure_join_bottom); holder.leaf = (ImageView) convertView .findViewById(R.id.lv_item_tree_structure_leaf); holder.joinBottom2 = (ImageView) convertView .findViewById(R.id.lv_item_tree_structure_join_bottom2); holder.leaf2 = (ImageView) convertView .findViewById(R.id.lv_item_tree_structure_leaf2); holder.tree = (ImageView) convertView .findViewById(R.id.lv_item_tree_structure_tree); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } holder.tree.setVisibility(View.GONE); holder.joinBottom.setVisibility(View.GONE); holder.leaf.setVisibility(View.GONE); holder.joinBottom2.setVisibility(View.GONE); holder.leaf2.setVisibility(View.GONE); // 如果是父级 if ("1".equals(dataItem.get("org_level"))) { holder.tree.setVisibility(View.VISIBLE); holder.joinBottom.setVisibility(View.GONE); holder.leaf.setVisibility(View.GONE); holder.joinBottom2.setVisibility(View.GONE); holder.leaf2.setVisibility(View.GONE); } else if ("2".equals(dataItem.get("org_level"))) {// 如果是子级 holder.joinBottom2.setVisibility(View.GONE); holder.leaf2.setVisibility(View.GONE); holder.tree.setVisibility(View.GONE); holder.joinBottom.setVisibility(View.VISIBLE); holder.leaf.setVisibility(View.VISIBLE); } else { // 3级 holder.tree.setVisibility(View.GONE); holder.joinBottom2.setVisibility(View.VISIBLE); holder.leaf2.setVisibility(View.VISIBLE); holder.joinBottom.setVisibility(View.VISIBLE); holder.leaf.setVisibility(View.VISIBLE); } try { holder.text.setText(dataItem.get("org_code").toString() + " " + dataItem.get("org_name").toString()); } catch (Exception e) { } final CheckBox cb = holder.cb; if (CHECKED_TRUE.equals(dataItem.get(IS_CHECKED))) { cb.setChecked(true); } else { cb.setChecked(false); } convertView.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { if (MotionEvent.ACTION_DOWN == event.getAction()) { if (cb.isChecked()) { cb.setChecked(false); dataItem.put(IS_CHECKED, CHECKED_FALSE); } else { cb.setChecked(true); dataItem.put(IS_CHECKED, CHECKED_TRUE); } if ("1".equals(dataItem.get("org_level").toString())) { // 遍历子营业部 HashMap
item = null; for (int i = position + 1; i < mDataList.size(); i++) { item = mDataList.get(i); if ("2".equals(item.get("org_level")) || "3".equals(item.get("org_level"))) { if (cb.isChecked()) { item.put(IS_CHECKED, CHECKED_TRUE); } else { item.put(IS_CHECKED, CHECKED_FALSE); } } else if ("1".equals(item.get("org_level"))) { break; }// end else if }// end for notifyDataSetChanged(); }// end if else if ("2".equals(dataItem.get("org_level").toString())) { // 遍历子营业部 HashMap
item = null; for (int i = position + 1; i < mDataList.size(); i++) { item = mDataList.get(i); if ("3".equals(item.get("org_level"))) { if (cb.isChecked()) { item.put(IS_CHECKED, CHECKED_TRUE); } else { item.put(IS_CHECKED, CHECKED_FALSE); } } else if ("1".equals(item.get("org_level"))) { break; }// end else if }// end for notifyDataSetChanged(); }// end else if return true; } return false; } }); return convertView; } /** * 拿到已选择营业部的代码字符串,代码之间逗号分隔 * * @return */ public String getSelectedOrgCodes() { StringBuilder sbOrgCodes = new StringBuilder(); for (int i = 0; i < mDataList.size(); i++) { if (mDataList.get(i).get(IS_CHECKED).equals(CHECKED_TRUE)) { if (sbOrgCodes.length() <= 2) { sbOrgCodes.append(mDataList.get(i).get("org_code") .toString()); } else { sbOrgCodes.append("," + mDataList.get(i).get("org_code").toString()); }// end else }// end if }// end for Log.i(TAG, "getSelectedOrgCodes: " + sbOrgCodes.toString()); return sbOrgCodes.toString(); } /** * 拿到已选择的营业部(org_code+org_name) * * @return */ public String getSelectedOrg() { StringBuilder sbOrg = new StringBuilder(); for (int i = 0; i < mDataList.size(); i++) { if (mDataList.get(i).get(IS_CHECKED).equals(CHECKED_TRUE)) { String strText = mDataList.get(i).get("org_code").toString() + " " + mDataList.get(i).get("org_name").toString(); if (sbOrg.length() <= 2) { sbOrg.append(strText); } else { sbOrg.append("," + strText); }// end else }// end if }// end for Log.i(TAG, "getSelectedOrg: " + sbOrg.toString()); return sbOrg.toString(); } /** * 默认全部选中 */ private void setDefaultChecked() { for (int i = 0; i < mDataList.size(); i++) { mDataList.get(i).put(IS_CHECKED, CHECKED_TRUE); } } class ViewHolder { TextView text; CheckBox cb; ImageView tree;// 树形图 ImageView joinBottom;// 连接线 ImageView leaf;// 子节点图 ImageView joinBottom2;// 3级连接线 ImageView leaf2;// 3级子节点图 }}

 

 单选营业部树形列表适配器

 

/** * 单选营业部树形列表适配器 *  * @author xinyan * @date 2013-5-27 */public class SingleChoiceIntOrgListAdapter extends BaseAdapter {	public static final String TAG = "SingleChoiceIntOrgListAdapter";	public static final String CHECKED_TRUE = "1";	public static final String CHECKED_FALSE = "0";	public static final String IS_CHECKED = "IS_CHECKED";	private List
> mDataList; private LayoutInflater mInflater; public SingleChoiceIntOrgListAdapter(Context context, List
> dataList) { this.mInflater = LayoutInflater.from(context); mDataList = dataList; } @Override public int getCount() { return mDataList.size(); } @Override public Object getItem(int position) { return mDataList.get(position); } @Override public long getItemId(int position) { return 0; } @Override public View getView(final int position, View convertView, ViewGroup parent) { ViewHolder holder = null; final HashMap
dataItem = mDataList.get(position); if (null == convertView) { holder = new ViewHolder(); convertView = mInflater.inflate( R.layout.lv_item_tree_structure_single_choice, null); holder.cb = (CheckBox) convertView .findViewById(R.id.lv_item_tree_structure_cb); holder.text = (TextView) convertView .findViewById(R.id.lv_item_tree_structure_text); holder.joinBottom = (ImageView) convertView .findViewById(R.id.lv_item_tree_structure_join_bottom); holder.leaf = (ImageView) convertView .findViewById(R.id.lv_item_tree_structure_leaf); holder.joinBottom2 = (ImageView) convertView .findViewById(R.id.lv_item_tree_structure_join_bottom2); holder.leaf2 = (ImageView) convertView .findViewById(R.id.lv_item_tree_structure_leaf2); holder.tree = (ImageView) convertView .findViewById(R.id.lv_item_tree_structure_tree); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } holder.tree.setVisibility(View.GONE); holder.joinBottom.setVisibility(View.GONE); holder.leaf.setVisibility(View.GONE); holder.joinBottom2.setVisibility(View.GONE); holder.leaf2.setVisibility(View.GONE); // 如果是父级 if ("1".equals(dataItem.get("org_level"))) { holder.tree.setVisibility(View.VISIBLE); holder.joinBottom.setVisibility(View.GONE); holder.leaf.setVisibility(View.GONE); holder.joinBottom2.setVisibility(View.GONE); holder.leaf2.setVisibility(View.GONE); } else if ("2".equals(dataItem.get("org_level"))) {// 如果是子级 holder.joinBottom2.setVisibility(View.GONE); holder.leaf2.setVisibility(View.GONE); holder.tree.setVisibility(View.GONE); holder.joinBottom.setVisibility(View.VISIBLE); holder.leaf.setVisibility(View.VISIBLE); } else { // 3级 holder.tree.setVisibility(View.GONE); holder.joinBottom2.setVisibility(View.VISIBLE); holder.leaf2.setVisibility(View.VISIBLE); holder.joinBottom.setVisibility(View.VISIBLE); holder.leaf.setVisibility(View.VISIBLE); } try { holder.text.setText(dataItem.get("org_code").toString() + " " + dataItem.get("org_name").toString()); } catch (Exception e) { } convertView.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { if (MotionEvent.ACTION_DOWN == event.getAction()) { dataItem.put(IS_CHECKED, CHECKED_TRUE); // 把其它的营业部设置为false for (int i = 0; i < mDataList.size(); i++) { if (i == position) { continue; } else { mDataList.get(i).put(IS_CHECKED, CHECKED_FALSE); } } } return false; } }); return convertView; } /** * 拿到已选择营业部的代码字符串,代码之间逗号分隔 * * @return */ public String getSelectedOrgCodes() { StringBuilder sbOrgCodes = new StringBuilder(); for (int i = 0; i < mDataList.size(); i++) { if (mDataList.get(i).get(IS_CHECKED).equals(CHECKED_TRUE)) { if (sbOrgCodes.length() <= 2) { sbOrgCodes.append(mDataList.get(i).get("org_code") .toString()); } else { sbOrgCodes.append("," + mDataList.get(i).get("org_code").toString()); }// end else }// end if }// end for Log.i(TAG, "getSelectedOrgCodes: " + sbOrgCodes.toString()); return sbOrgCodes.toString(); } /** * 拿到已选择的营业部(org_code+org_name) * * @return */ public String getSelectedOrg() { StringBuilder sbOrg = new StringBuilder(); for (int i = 0; i < mDataList.size(); i++) { if (mDataList.get(i).get(IS_CHECKED).equals(CHECKED_TRUE)) { String strText = mDataList.get(i).get("org_code").toString() + " " + mDataList.get(i).get("org_name").toString(); if (sbOrg.length() <= 2) { sbOrg.append(strText); } else { sbOrg.append("," + strText); }// end else }// end if }// end for Log.i(TAG, "getSelectedOrg: " + sbOrg.toString()); return sbOrg.toString(); } /** * 默认全部选中 */ private void setDefaultChecked() { for (int i = 0; i < mDataList.size(); i++) { mDataList.get(i).put(IS_CHECKED, CHECKED_TRUE); } } /** * 设置默认选中的营业部 * * @param orgCode */ public void setDefaultChecked(String orgCode) { for (int i = 0; i < mDataList.size(); i++) { if (orgCode.contains(mDataList.get(i).get("org_code").toString())) { mDataList.get(i).put(IS_CHECKED, CHECKED_TRUE); } else { // 因为查询框里使用的多选营业部框跟这里使用的一个数据源, // 为了避免其它地方对这造成的影响,所以全部初始化好 mDataList.get(i).put(IS_CHECKED, CHECKED_FALSE); } } } class ViewHolder { TextView text; CheckBox cb; ImageView tree;// 树形图 ImageView joinBottom;// 连接线 ImageView leaf;// 子节点图 ImageView joinBottom2;// 3级连接线 ImageView leaf2;// 3级子节点图 }}

 

ListView的item布局

 

 

父级标志图

子级标志图

父级和子级的连接线

 

转载于:https://www.cnblogs.com/james1207/p/3271487.html

你可能感兴趣的文章
Java -- Swing 组件使用
查看>>
Software--Architecture--DesignPattern IoC, Factory Method, Source Locator
查看>>
poj1936---subsequence(判断子串)
查看>>
黑马程序员_Java基础枚举类型
查看>>
【redis4 】
查看>>
[ python ] 练习作业 - 2
查看>>
一位90后程序员的自述:如何从年薪3w到30w!
查看>>
在.net core上使用Entity FramWork(Db first)
查看>>
Eclipse中如何开启断言(Assert),方法有二
查看>>
System.Net.WebException: 无法显示错误消息,原因是无法找到包含此错误消息的可选资源程序集...
查看>>
压缩图片 待验证
查看>>
UIImage 和 iOS 图片压缩UIImage / UIImageVIew
查看>>
MongoDB的数据库、集合的基本操作
查看>>
ajax向后台传递数组
查看>>
疯狂JAVA16课之对象与内存控制
查看>>
[转载]树、森林和二叉树的转换
查看>>
WPF移动Window窗体(鼠标点击左键移动窗体自定义行为)
查看>>
软件测试-----Graph Coverage作业
查看>>
django ORM创建数据库方法
查看>>
创建Oracle synonym 详解
查看>>