目前已经实现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布局
父级和子级的连接线