package com.isoftston.issuser.conchapp.views.security; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.AdapterView; import android.widget.ListView; import android.widget.Toast; import com.corelibs.base.BaseActivity; import com.isoftston.issuser.conchapp.R; import com.isoftston.issuser.conchapp.adapters.NodeTreeAdapter; import com.isoftston.issuser.conchapp.constants.Constant; import com.isoftston.issuser.conchapp.model.bean.OrgBean; import com.isoftston.issuser.conchapp.model.bean.SafeListBean; import com.isoftston.issuser.conchapp.model.bean.SecuritySearchBean; import com.isoftston.issuser.conchapp.model.bean.UserInfoBean; import com.isoftston.issuser.conchapp.presenter.SecurityPresenter; import com.isoftston.issuser.conchapp.utils.Node; import com.isoftston.issuser.conchapp.utils.NodeHelper; import com.isoftston.issuser.conchapp.views.interfaces.SecuryView; import com.isoftston.issuser.conchapp.weight.NavBar; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import butterknife.Bind; /** * Created by issuser on 2018/4/26. */ public class OrgActivity extends BaseActivity<SecuryView,SecurityPresenter> implements SecuryView { private Context context = OrgActivity.this; private NodeTreeAdapter mAdapter; private LinkedList<Node> mLinkedList = new LinkedList<>(); private List<Node> data = new ArrayList<>(); private static final String TAG = OrgActivity.class.getSimpleName(); private final Integer FIND_RESULT_CODE = 130; private final Integer HIDDEN_RESULT_CODE = 131; private int code; private int pos; //记录已请求的记录 private List<Integer> posList = new ArrayList<>(); public static Intent getLaucnher(Context context,int i){//根据code设置头部标题文字 Intent intent =new Intent(context,OrgActivity.class); intent.putExtra("code",i); return intent; } @Bind(R.id.id_tree) ListView mListView; @Bind(R.id.nav) NavBar nav; @Override protected int getLayoutId() { return R.layout.org_select_dept_layout; } @Override protected void init(Bundle savedInstanceState) { code = getIntent().getIntExtra("code",-1); nav.setColorRes(R.color.white); nav.setTitleColor(getResources().getColor(R.color.black)); setBarColor(getResources().getColor(R.color.transparent_black)); nav.showBack(2); if(0 == code) { nav.setNavTitle(getString(R.string.find_company)); } else if(1 == code) { nav.setNavTitle(getString(R.string.trouble_company)); }else if (2==code){ nav.setNavTitle(getString(R.string.work_company)); } mAdapter = new NodeTreeAdapter(context,mListView,mLinkedList); mListView.setAdapter(mAdapter); mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) { Node node = (Node)mAdapter.getItem(position); //Toast.makeText(getApplicationContext(),"选中2:"+ node.get_label(),Toast.LENGTH_SHORT).show(); Log.i(TAG,"node pos:" + position + ",node name:" + node.get_label() + ",node id:" + node.get_id() + ",node child:" + node.hasChild()); //下一级请求 if(node.hasChild()) { pos = position; if(!posList.contains(pos)) { presenter.getCompanyChoiceNextList((String)node.get_id()); posList.add(pos); } else { mAdapter.expandOrCollapse(pos); } } else { //选中单位 Intent intent =new Intent(); if(0 == code||2==code) { intent.putExtra(Constant.FIND_COMPANY_NAME,node.get_label()); intent.putExtra(Constant.FIND_COMPANY_ID,(String)node.get_id()); setResult(FIND_RESULT_CODE,intent); } else if(1 == code) { intent.putExtra(Constant.DANGER_COMPANY_NAME,node.get_label()); intent.putExtra(Constant.DANGER_COMPANY_ID,(String)node.get_id()); setResult(HIDDEN_RESULT_CODE,intent); } finish(); } } }); presenter.getCompanyChoiceList(); } @Override protected SecurityPresenter createPresenter() { return new SecurityPresenter(); } @Override public void onLoadingCompleted() { } @Override public void onAllPageLoaded() { } @Override public void addSuccess() { } @Override public void getSafeListSuccess(SafeListBean data) { } @Override public void addFailed() { } @Override public void getSafeChoiceList(SecuritySearchBean bean) { data.addAll(bean.ORG); mLinkedList.addAll(NodeHelper.sortNodes(data)); mLinkedList = NodeHelper.sortLinkedNodes(mLinkedList); data.clear(); mAdapter.notifyDataSetChanged(); } @Override public void getOrgList(List<OrgBean> bean) { data.addAll(bean); mLinkedList.addAll(NodeHelper.sortNodes(data)); mLinkedList = NodeHelper.sortLinkedNodes(mLinkedList); mAdapter.notifyDataSetChanged(); mAdapter.expandOrCollapse(pos); } @Override public void getOrgId(String orgId) { } @Override public void getWorkError() { } @Override public void setUserInfo(UserInfoBean userInfo) { } }
==================工具类==============
package com.isoftston.issuser.conchapp.utils; import com.isoftston.issuser.conchapp.R; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; /** * Created by HQOCSHheqing on 2016/8/2. * * @description 节点帮助类 */ public class NodeHelper { public static LinkedList<Node> sortLinkedNodes(LinkedList<Node> tmpNodeList){ LinkedList<Node> nodeList = new LinkedList<>(); nodeList.addAll(tmpNodeList); LinkedList<Node> rootNodes = new LinkedList<>(); int size = nodeList.size(); Node m; Node n; //两个for循环整理出所有数据之间的斧子关系,最后会构造出一个森林(就是可能有多棵树) for (int i = 0;i < size;i++){ m = nodeList.get(i); for (int j = i+1;j < size;j++){ n = nodeList.get(j); if (m.parent(n)){ m.get_childrenList().add(n); n.set_parent(m); }else if (m.child(n)){ n.get_childrenList().add(m); m.set_parent(n); } } } //找出所有的树根,同事设置相应的图标(后面你会发现其实这里的主要 // 作用是设置叶节点和非叶节点的图标) for (int i = 0;i < size;i++){ m = nodeList.get(i); if (m.isRoot()){ rootNodes.add(m); } setNodeIcon(m); } nodeList.clear();//此时所有的关系已经整理完成了 // ,森林构造完成,可以清空之前的数据,释放内存,提高性能 // ,如果之前的数据还有用的话就不清空 nodeList = rootNodes;//返回所有的根节点 rootNodes = null; return nodeList; } /** * 传入所有的要展示的节点数据 * @param tmpNodeList 返回值是所有的根节点 * @return */ public static List<Node> sortNodes(List<Node> tmpNodeList){ List<Node> nodeList = new ArrayList<>(); nodeList.addAll(tmpNodeList); List<Node> rootNodes = new ArrayList<>(); int size = nodeList.size(); Node m; Node n; //两个for循环整理出所有数据之间的斧子关系,最后会构造出一个森林(就是可能有多棵树) for (int i = 0;i < size;i++){ m = nodeList.get(i); for (int j = i+1;j < size;j++){ n = nodeList.get(j); if (m.parent(n)){ m.get_childrenList().add(n); n.set_parent(m); }else if (m.child(n)){ n.get_childrenList().add(m); m.set_parent(n); } } } //找出所有的树根,同事设置相应的图标(后面你会发现其实这里的主要 // 作用是设置叶节点和非叶节点的图标) for (int i = 0;i < size;i++){ m = nodeList.get(i); if (m.isRoot()){ rootNodes.add(m); } setNodeIcon(m); } nodeList.clear();//此时所有的关系已经整理完成了 // ,森林构造完成,可以清空之前的数据,释放内存,提高性能 // ,如果之前的数据还有用的话就不清空 nodeList = rootNodes;//返回所有的根节点 rootNodes = null; return nodeList; } /** * 设置图标 * @param node */ private static void setNodeIcon(Node node){ if (!node.isLeaf()){ if (node.isExpand()){ node.set_icon(R.mipmap.collapse); }else{ node.set_icon(R.mipmap.expand2); } }else{ node.set_icon(-1); } } }
===========javabean===========================
package com.isoftston.issuser.conchapp.model.bean; import android.util.Log; import com.isoftston.issuser.conchapp.utils.Node; /** * Created by issuser on 2018/4/26. */ public class OrgBean extends Node<String> { private static final String TAG = OrgBean.class.getSimpleName(); /** * 此处返回节点ID * @return */ @Override public String get_id() { return ID_; } /** * 此处返回父亲节点ID * @return */ @Override public String get_parentId() { return PARENT_ID_; } @Override public String get_label() { return ORG_NAME_; } @Override public boolean parent(Node dest) { if(ID_ == null) { return false; } if (ID_ .equals(dest.get_parentId())){ return true; } return false; } @Override public boolean child(Node dest) { if(PARENT_ID_ == null) { return false; } if (PARENT_ID_.equals(dest.get_id())){ return true; } return false; } @Override public boolean hasChild() { return HASCHILD.equals("1"); } private String ID_; public String getPARENT_ID_() { return PARENT_ID_; } public void setPARENT_ID_(String PARENT_ID_) { this.PARENT_ID_ = PARENT_ID_; } private String PARENT_ID_; private String ORG_NAME_; private String ISCOMPANY_; private String HASCHILD = "1"; public String getID_() { return ID_; } public void setID_(String ID_) { this.ID_ = ID_; } public String getORG_NAME_() { return ORG_NAME_; } public void setORG_NAME_(String ORG_NAME_) { this.ORG_NAME_ = ORG_NAME_; } public String getISCOMPANY_() { return ISCOMPANY_; } public void setISCOMPANY_(String ISCOMPANY_) { this.ISCOMPANY_ = ISCOMPANY_; } public String getHASCHILD() { return HASCHILD; } public void setHASCHILD(String HASCHILD) { this.HASCHILD = HASCHILD; } }
===============适配器adpter==================
package com.isoftston.issuser.conchapp.adapters; import android.app.ActionBar; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.TextView; import com.isoftston.issuser.conchapp.R; import com.isoftston.issuser.conchapp.utils.Node; import com.isoftston.issuser.conchapp.utils.NodeHelper; import java.util.LinkedList; import java.util.List; /** * Created by HQOCSHheqing on 2016/8/3. * * @description 适配器类,就是listview最常见的适配器写法 */ public class NodeTreeAdapter extends BaseAdapter{ //大家经常用ArrayList,但是这里为什么要使用LinkedList // ,后面大家会发现因为这个list会随着用户展开、收缩某一项而频繁的进行增加、删除元素操作, // 因为ArrayList是数组实现的,频繁的增删性能低下,而LinkedList是链表实现的,对于频繁的增删 //操作性能要比ArrayList好。 private LinkedList<Node> nodeLinkedList; private LayoutInflater inflater; private int retract;//缩进值 private Context context; public NodeTreeAdapter(Context context,ListView listView,LinkedList<Node> linkedList){ inflater = LayoutInflater.from(context); this.context = context; nodeLinkedList = linkedList; listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { expandOrCollapse(position); } }); //缩进值,大家可以将它配置在资源文件中,从而实现适配 retract = (int)(context.getResources().getDisplayMetrics().density*10+0.5f); } /** * 展开或收缩用户点击的条目 * @param position */ public void expandOrCollapse(int position){ Node node = nodeLinkedList.get(position); if (node != null && !node.isLeaf()){ boolean old = node.isExpand(); if (old){ List<Node> nodeList = node.get_childrenList(); int size = nodeList.size(); Node tmp = null; for (int i = 0;i < size;i++){ tmp = nodeList.get(i); if (tmp.isExpand()){ collapse(tmp,position+1); } nodeLinkedList.remove(position+1); } }else{ nodeLinkedList.addAll(position + 1, node.get_childrenList()); } node.setIsExpand(!old); notifyDataSetChanged(); } } /** * 递归收缩用户点击的条目 * 因为此中实现思路是:当用户展开某一条时,就将该条对应的所有子节点加入到nodeLinkedList * ,同时控制缩进,当用户收缩某一条时,就将该条所对应的子节点全部删除,而当用户跨级缩进时 * ,就需要递归缩进其所有的孩子节点,这样才能保持整个nodeLinkedList的正确性,同时这种实 * 现方式避免了每次对所有数据进行处理然后插入到一个list,最后显示出来,当数据量一大,就会卡顿, * 所以这种只改变局部数据的方式性能大大提高。 * @param position */ private void collapse(Node node,int position){ node.setIsExpand(false); List<Node> nodes = node.get_childrenList(); int size = nodes.size(); Node tmp = null; for (int i = 0;i < size;i++){ tmp = nodes.get(i); if (tmp.isExpand()){ collapse(tmp,position+1); } nodeLinkedList.remove(position+1); } } @Override public int getCount() { return nodeLinkedList.size(); } @Override public Object getItem(int position) { return nodeLinkedList.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { final ViewHolder holder; if (convertView == null){ convertView = inflater.inflate(R.layout.org_tree_listview_item,null); holder = new ViewHolder(); holder.imageView = (ImageView)convertView.findViewById(R.id.id_treenode_icon); holder.label = (TextView)convertView.findViewById(R.id.id_treenode_label); holder.confirm = (LinearLayout)convertView.findViewById(R.id.id_confirm); convertView.setTag(holder); }else{ holder = (ViewHolder)convertView.getTag(); } Node node = nodeLinkedList.get(position); holder.label.setText(node.get_label()); if(node.get_icon() == -1){ holder.imageView.setVisibility(View.INVISIBLE); }else{ ViewGroup.LayoutParams params = holder.imageView.getLayoutParams(); holder.imageView.setLayoutParams(params); holder.imageView.setVisibility(View.VISIBLE); holder.imageView.setImageResource(node.get_icon()); } holder.confirm.setTag(position); // holder.confirm.setOnClickListener(new View.OnClickListener() { // @Override // public void onClick(View v) { // Toast.makeText(context,"选中:"+v.getTag(),Toast.LENGTH_SHORT).show(); // Node node = (Node)getItem((Integer)v.getTag()); // Toast.makeText(context,"选中:"+node.get_label(),Toast.LENGTH_SHORT).show(); // // } // }); convertView.setPadding(node.get_level()*retract,5,5,5); return convertView; } static class ViewHolder{ public ImageView imageView; public TextView label; public LinearLayout confirm; } }
========================node==============
package com.isoftston.issuser.conchapp.utils; import com.isoftston.issuser.conchapp.R; import java.util.ArrayList; import java.util.List; /** * Created by HQOCSHheqing on 2016/8/2. * * @description 节点抽象类(泛型T主要是考虑到ID和parentID有可能是int型也有可能是String型 * 即这里可以传入Integer或者String,具体什么类型由子类指定 ,因为这两种类型比较是否相等的方式不同:一个是用 “==”,一个是用 equals() 函数) */ public abstract class Node<T> { private int _level = -1;//当前节点的层级,初始值-1 后面会讲到 private List<Node> _childrenList = new ArrayList<>();//所有的孩子节点 private Node _parent;//父亲节点 private int _icon;//图标资源ID private boolean isExpand = false;//当前状态是否展开 public abstract T get_id();//得到当前节点ID public abstract T get_parentId();//得到当前节点的父ID public abstract String get_label();//要显示的内容 public abstract boolean parent(Node dest);//判断当前节点是否是dest的父亲节点 public abstract boolean child(Node dest);//判断当前节点是否是dest的孩子节点 public abstract boolean hasChild(); //判断当前节点是否是叶子节点 public int get_level() { if (_level == -1){//如果是 -1 的话就递归获取 //因为是树形结构,所以此处想要得到当前节点的层级 //,必须递归调用,但是递归效率低下,如果每次都递归获取会严重影响性能,所以我们把第一次 //得到的结果保存起来避免每次递归获取 int level = _parent == null ? 1 : _parent.get_level()+1; _level = level; return _level; } return _level; } public void set_level(int _level) { this._level = _level; } public List<Node> get_childrenList() { return _childrenList; } public void set_childrenList(List<Node> _childrenList) { this._childrenList = _childrenList; } public Node get_parent() { return _parent; } public void set_parent(Node _parent) { this._parent = _parent; } public int get_icon() { return _icon; } public void set_icon(int _icon) { this._icon = _icon; } public boolean isExpand() { return isExpand; } public void setIsExpand(boolean isExpand) { this.isExpand = isExpand; if (isExpand){ _icon = R.mipmap.collapse; }else{ _icon = R.mipmap.expand2; } } public boolean isRoot(){ return _parent == null; } public boolean isLeaf(){ return !hasChild(); } }
===org_tree_listview_item===========
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content"> <ImageView android:id="@+id/id_treenode_icon" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_marginLeft="5dp" android:layout_marginRight="5dp" android:src="@mipmap/expand2" /> <!--保证整块区域可点,使用户好点击--> <LinearLayout android:id="@+id/id_confirm" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_alignParentRight="true" android:layout_centerVertical="true" android:clickable="true" android:paddingBottom="8dp" android:paddingLeft="15dp" android:paddingRight="15dp" android:paddingTop="8dp"> <ImageView android:layout_width="25dp" android:layout_height="25dp" android:scaleType="centerInside" /> </LinearLayout> <TextView android:id="@+id/id_treenode_label" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_toLeftOf="@id/id_confirm" android:layout_toRightOf="@id/id_treenode_icon" android:textColor="@android:color/black" android:textSize="12sp" /> </RelativeLayout>
====activity布局========
<?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:layout_height="match_parent"> <com.isoftston.issuser.conchapp.weight.NavBar android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/nav" /> <ListView android:layout_width="match_parent" android:layout_height="wrap_content" android:divider="@color/line" android:dividerHeight="1dp" android:scrollbars="none" android:id="@+id/id_tree" /> </LinearLayout>