第三方框架AndroidTreeView官方網址Github Demo其中使用到一個 第三方圖標框架Print 。
不使用圖標庫框架Print(因爲不需要)。
分析第三方框架AndroidTreeView:
每一層使用LinearLayout添加內部節點(TreeNodeWrapperView)。
一、實現的功能
默認顯示所有年級名稱;點擊某一個年級,加載其所有班級名稱;點擊某一班級,加載其所有學生名稱。年級、班級單選,學生可多選。選擇的項文字變紅,沒選擇的是黑色。相應的箭頭會根據狀態改變。
二、運行效果
三、功能代碼
因爲功能需求,在library的AndroidTreeView中新增了一個方法:
//新增函數:只展開自己;收縮自己及子節點
public void toggleNode(TreeNode node,boolean includeSubnodes) {
if (node.isExpanded()) {
collapseNode(node, includeSubnodes);//收縮所有,包括子節點
} else {
expandNode(node, false);//只展開自己
}
}
Fragment代碼:
功能邏輯處理整個過程
public class MoreListFragment extends Fragment {
private TextView tvShow;
private ViewGroup containerView;
private AndroidTreeView tView;
private TreeNode choseGradeNode;//已選的年級節點
private String choseGradeStr;//已選的年級值
private List<TreeNode> initGradeList = new ArrayList<>();//已初始化班級節點的年級
private TreeNode choseClassNode;//已選的班級節點
private String choseClassStr;//已選的班級值
private List<TreeNode> initClassList = new ArrayList<>();//已初始化學生節點的班級
private List<String> choseStudentList = new ArrayList<>();//已選的學生值
private int nodeCount = 0;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_default, null, false);
containerView = (ViewGroup) rootView.findViewById(R.id.container);
tvShow = (TextView) rootView.findViewById(R.id.status_bar);
initGradeNodes();
return rootView;
}
/**
* 初始化年級節點
*/
private void initGradeNodes(){
TreeNode root = TreeNode.root();
for (int i = 0; i < 3; i++) {
TreeNode areaNode = new TreeNode(new TreeNodeHolder.IconTreeItem("grade_" + i, "" + nodeCount,0));
nodeCount++;
root.addChildren(areaNode);
}
tView = new AndroidTreeView(getActivity(), root);
tView.setDefaultAnimation(true);
tView.setUseAutoToggle(false);//不使用自動展開收縮
tView.setDefaultContainerStyle(R.style.TreeNodeStyleCustom);//TreeNodeStyleCustom、 TreeNodeStyleDivided
tView.setDefaultViewHolder(TreeNodeHolder.class);
tView.setDefaultNodeClickListener(nodeClickListener);
containerView.addView(tView.getView());
}
/**
* 初始化指定班級節點下的所有班級節點
* @param gradeNode 年級節點
*/
private void initClassNodes(TreeNode gradeNode){
for (int j = 0; j < 3; j++) {
TreeNode classNode = new TreeNode(new TreeNodeHolder.IconTreeItem("class_" + j, "" + nodeCount,1));
nodeCount++;
tView.addNode(gradeNode,classNode);
}
initGradeList.add(gradeNode);
}
/**
* 初始化指定班級節點下的所有學生節點
* @param classNode 班級節點
*/
private void initStudentNodes(TreeNode classNode){
for (int j = 0; j < 3; j++) {
TreeNode studentNode = new TreeNode(new TreeNodeHolder.IconTreeItem("student_" + j, "" + nodeCount,2));
nodeCount++;
tView.addNode(classNode,studentNode);
}
initClassList.add(classNode);
}
/**
* 多級樹節點點擊事件
*/
private TreeNode.TreeNodeClickListener nodeClickListener = new TreeNode.TreeNodeClickListener() {
@Override
public void onClick(TreeNode node, Object value) {
TreeNodeHolder.IconTreeItem item = (TreeNodeHolder.IconTreeItem) value;
switch (item.level){
case 0:
choseClassNode = null;
choseClassStr = "";
choseStudentList.clear();
if (choseGradeNode != null){//之前已選過節點
TreeNodeHolder.IconTreeItem choseAreaNodeValue = (TreeNodeHolder.IconTreeItem) choseGradeNode.getValue();
if (!item.id.equals(choseAreaNodeValue.id)) {
//此節點 != 上次選擇的節點,則取消、收縮上次的節點及其子節點
tView.toggleNode(choseGradeNode, true);
}
}
choseGradeNode = node;
tView.toggleNode(node, true);//只展開此節點或收縮此節點及其子節點
if(node.isExpanded()){//選擇此節點
choseGradeStr = item.text;
if(!initGradeList.contains(node)){//此節點還未初始化過子節點
initClassNodes(node);
}
}else {//取消此節點
choseGradeStr = "";
choseGradeNode = null;
}
break;
case 1:
choseStudentList.clear();
if (choseClassNode != null){//之前已選過節點
TreeNodeHolder.IconTreeItem choseHspNodeValue = (TreeNodeHolder.IconTreeItem) choseClassNode.getValue();
if (!item.id.equals(choseHspNodeValue.id)) {
//此節點 != 上次選擇的節點,則取消、收縮上次的節點
tView.toggleNode(choseClassNode, true);
}
}
choseClassNode = node;
tView.toggleNode(node, true);//只展開此節點或收縮此節點及其子節點
if(node.isExpanded()){//選擇此節點
choseClassStr = item.text;
if(!initClassList.contains(node)){//此節點還未初始化過子節點
initStudentNodes(node);
}
}else {//取消此節點
choseClassStr = "";
choseClassNode = null;
}
break;
case 2:
if(!choseStudentList.contains(item.text)){
choseStudentList.add(item.text);
}else {
choseStudentList.remove(item.text);
}
tView.toggleNode(node, true);
break;
}
tvShow.setText("["+choseGradeStr+"]_["+choseClassStr+"]_"+choseStudentList.toString());
}
};
}
ViewHolder:
public class TreeNodeHolder extends TreeNode.BaseNodeViewHolder<TreeNodeHolder.IconTreeItem> {
private TextView tvValue;
private ImageView ivArrowIcon;
public TreeNodeHolder(Context context) {
super(context);
}
@Override
public View createNodeView(final TreeNode node, final IconTreeItem value) {
final LayoutInflater inflater = LayoutInflater.from(context);
final View view = inflater.inflate(R.layout.item_tree_node, null, false);
tvValue = (TextView) view.findViewById(R.id.node_value);
tvValue.setText(value.text);
ivArrowIcon = (ImageView) view.findViewById(R.id.iv_arrow_icon);
if (value.level == 2) {
ivArrowIcon.setVisibility(View.GONE);
}
return view;
}
@Override
public void toggle(boolean active) {
ivArrowIcon.setImageDrawable(context.getResources().getDrawable(active ? R.mipmap.ic_node_open:R.mipmap.ic_node_close));
tvValue.setTextColor(context.getResources().getColor(active ? R.color.text_red : R.color.text_black));
}
public static class IconTreeItem {
public String text;//文字
public String id;
public int level;
public IconTreeItem(String text,String id,int level) {
this.text = text;
this.id = id;
this.level = level;
}
}
}
fragment的佈局:
<?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="match_parent">
<TextView
android:padding="8dp"
android:textSize="16sp"
android:text="Last Clicked:"
android:layout_alignParentTop="true"
android:background="@android:color/holo_blue_dark"
android:id="@+id/status_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<RelativeLayout
android:layout_below="@id/status_bar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/container"></RelativeLayout>
</RelativeLayout>
item的佈局:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:minHeight="48dp"
android:gravity="center_vertical"
android:background="?android:attr/selectableItemBackground"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:id="@+id/iv_arrow_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:gravity="center"
android:src="@mipmap/ic_node_close"
android:scaleType="centerInside"/>
<TextView
android:textSize="16sp"
android:layout_marginLeft="10dp"
android:id="@+id/node_value"
android:textColor="@color/text_black"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</RelativeLayout>