目前已经实现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<String, String> 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<String, String>();
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<String, String> param = new HashMap<String, String>();
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<String, String> map = new HashMap<String, String>();
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<HashMap<String, Object>> dataList = new ArrayList<HashMap<String, Object>>();
HashMap<String, Object> dataItem = null; for (int i = 0; i < array.length(); i++) {
dataItem = new HashMap<String, Object>(); 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<HashMap<String, Object>> regroupData(
List<HashMap<String, Object>> dataList) {
HashMap<String, Object> item = null;
ArrayList<HashMap<String, Object>> 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<String, Object> item2 = null; ArrayList<HashMap<String, Object>> 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<HashMap<String, Object>>();
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<String, Object> 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<HashMap<String, Object>> childList = null;
if (null != parentOrgItem.get("child")) {
childList = (ArrayList<HashMap<String, Object>>) parentOrgItem
.get("child");
} else {
childList = new ArrayList<HashMap<String, Object>>();
} // 检查子营业部列表是否已经存在该营业部
boolean isOrgExist = false;
if (childList.size() > 0) {
HashMap<String, Object> childItem = null; for (int k = 0; k < childList.size(); k++) {
childItem = (HashMap<String, Object>) 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<String, Object> childOrgItem = null; ArrayList<HashMap<String, Object>> childList = new ArrayList<HashMap<String, Object>>(); // 遍历列表是否存在子营业部
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<String, Object>>();
HashMap<String, Object> 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<HashMap<String, Object>> childList = (ArrayList<HashMap<String, Object>>) tempItem
.get("child");
HashMap<String, Object> childItem = null;
if (childList.size() > 0) {
for (int j = 0; j < childList.size(); j++) {
childItem = (HashMap<String, Object>) childList
.get(j);
regroupedDataList.add(childItem); // 检查子营业部是否还有子营业部
if (childItem.containsKey("child")) {
ArrayList<HashMap<String, Object>> childList2 = (ArrayList<HashMap<String, Object>>) childItem
.get("child");
HashMap<String, Object> childItem2 = null;
if (childList2.size() > 0) {
for (int k = 0; k < childList2.size(); k++) {
childItem2 = (HashMap<String, Object>) 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<HashMap<String, Object>> mDataList; private LayoutInflater mInflater; public MultiCheckIntOrgListAdapter(Context context,
List<HashMap<String, Object>> 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<String, Object> 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<String, Object> 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<String, Object> 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<HashMap<String, Object>> mDataList; private LayoutInflater mInflater; public SingleChoiceIntOrgListAdapter(Context context,
List<HashMap<String, Object>> 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<String, Object> 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布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<ImageView
android:id="@+id/lv_item_tree_structure_tree"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_gravity="center_vertical"
android:scaleType="fitXY"
android:src="@drawable/customer_account_mgr"
android:visibility="gone" />
<ImageView
android:id="@+id/lv_item_tree_structure_join_bottom"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_gravity="center_vertical"
android:scaleType="fitXY"
android:src="@drawable/joinbottom"
android:visibility="gone" />
<ImageView
android:id="@+id/lv_item_tree_structure_leaf"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_gravity="center_vertical"
android:scaleType="fitXY"
android:src="@drawable/leaf"
android:visibility="gone" />
<ImageView
android:id="@+id/lv_item_tree_structure_join_bottom2"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_gravity="center_vertical"
android:scaleType="fitXY"
android:src="@drawable/joinbottom"
android:visibility="gone" />
<ImageView
android:id="@+id/lv_item_tree_structure_leaf2"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_gravity="center_vertical"
android:scaleType="fitXY"
android:src="@drawable/leaf"
android:visibility="gone" />
<CheckBox
android:id="@+id/lv_item_tree_structure_cb"
style="@style/custom_checkbox"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_gravity="center_vertical"
android:layout_marginLeft="5dp"
android:clickable="false" />
<TextView
android:id="@+id/lv_item_tree_structure_text"
android:layout_width="400dp"
android:layout_height="40dp"
android:gravity="center_vertical"
android:paddingLeft="10dp"
android:textColor="@color/black"
android:textSize="20sp" />
</LinearLayout>

父级标志图


子级标志图

父级和子级的连接线

Android - N级树形结构实现的更多相关文章

  1. 使用Oracle数据库实现树形结构表的子-父级递归查询和删除,通过级联菜单简单举例

    前言: 我们在开发中,常常遇到单表的子-父id级联的表结构,在树形的深度不确定的情况下,一次查询出某个树形结构下的所有具有子-父级关系的数据变得十分困难. 这时,我们使用oracle提供的CONNEC ...

  2. 使用Oracle数据库实现树形结构表的子-父级迭代(递归)查询和删除,通过级联菜单简单举例

    前言: 我们在开发中,常常遇到单表的子-父id级联的表结构,在树形的深度不确定的情况下,一次查询出某个树形结构下的所有具有子-父级关系的数据变得十分困难. 这时,我们使用oracle提供的CONNEC ...

  3. C# 把带有父子关系的数据转化为------树形结构的数据 ,以及 找出父子级关系的数据中里面的根数据Id

    紧接上一篇,将List<Menu>的扁平结构数据, 转换成树形结构的数据 返回给前端   ,   废话不多说,开撸! --------------------- 步骤: 1. 建 Menu ...

  4. 22.Android之ExpandableListView树形列表学习

    Android经常用到树形菜单,一般ExpandableListView可以满足这个需要,今天学习下. XML代码: <?xml version="1.0" encoding ...

  5. 使用RecyclerView写树形结构的TreeRecyclerView

    简单介绍 android是不提供树形控件的,假设须要使用树形控件.我们应该怎么做呢? 先看效果 上图是一个明显的树形结构 实现原理 在逻辑上,它们是包括关系.数据结构上是多叉树,这是毋庸置疑的. 可是 ...

  6. Android 4.0 源代码结构

    Android源码的第一级目录结构   Android/abi (abi相关代码.ABI:application binary interface,应用程序二进制接口)   Android/bioni ...

  7. Linux/Ubuntu tree 命令以树形结构显示文件夹目录结构

    1.安装命令工具 sudo apt-get -y install tree 2.可以查看关于tree命令的帮助信息 $ tree --help usage: tree [-adfghilnpqrstu ...

  8. VBA读取文件夹下所有文件夹及文件内容,并以树形结构展示

    Const TR_LEVEL_MARK = "+"Const TR_COL_INDEX = "A"Const TR_COL_LEVEL = "E&qu ...

  9. Android无限级树状结构

    通过对ListView简单的扩展.再封装,即可实现无限层级的树控件TreeView. package cn.asiontang.nleveltreelistview; import android.a ...

随机推荐

  1. VC++判断是否连网

    在开发中,需要判断是否有网络连接,于是写了个函数,实现代码如下: //判断是否有网络连接 static BOOL DoHaveInternetConnection() { BOOL bRet = FA ...

  2. Linux下搭建Oracle11g RAC(8)----创建ASM磁盘组

    以grid用户创建ASM磁盘组,创建的ASM磁盘组为下一步创建数据库提供存储. ① grid用户登录图形界面,执行asmca命令来创建磁盘组: ② 进入ASMCA配置界面后,单击Create,创建新的 ...

  3. WPF加载Winform窗体时 报错:子控件不能为顶级窗体

    一.wpf项目中引用WindowsFormsIntegration和System.Windows.Forms 二.Form1.Designer.cs 的 partial class Form1 设置为 ...

  4. Codeforces Round #310 (Div. 2)--B

    http://codeforces.com/problemset/problem/556/B 题意:给定n个数字且都小于n,然后每次循环第2k+1个数字+1,第2k个数字减一,k=0,1,2...n/ ...

  5. Java SE (1)之 JFrame 组件 GridLayout布局

    package com.sunzhiyan; import java.awt.*; import javax.swing.*; public class Demo_2 extends JFrame{ ...

  6. enableEventValidation

    回发或回调参数无效.在配置中使用 <pages enableEventValidation="true"/> 或在页面中使用 <%@ Page EnableEve ...

  7. Android本地JUnit Text

    Android本地JUnit Text 步骤 创建一个和source文件,里面添加和src目录相同的包. 在AndroidManifest.xml文件manifest根节点添加如下文件 <ins ...

  8. javascript-图片横向无缝隙滚动(可在服务器运行)

    前两次弄'图片横向滚动'javascript,在本地上运行得很美,可是一上到我们学校后台的服务器,就有很多问题,这个算是行的了. css代码: <style type="text/cs ...

  9. vsftpd服务安装,配置,限制目录

    一.下载版本:vsftpd-2.0.5-16.el5_4.1.i386.rpm 二.安装:rpm -ivh vsftpd-2.0.5-16.el5_4.1.i386.rpm 三.配置: vsftpd. ...

  10. Oracle计算时间函数(numtodsinterval、numtoyminterval)

    numtodsinterval(<x>,<c>) ,x是一个数字,c是一个字符串,表明x的单位,这个函数把x转为interval day to second数据类型 常用的单位 ...