This article refers to Hongyang's Great God article. http://blog.csdn.net/lmj623565791/article/details/40212367 Write a demo for yourself.
Look at the picture first.
General idea:
Think of each data as an item in a listview, sorting the items from top to bottom according to their relationship. Then each item is set to a different display state, and clicking on each item will link the display state changes of other corresponding items, thus achieving the goal of tree structure navigation.
1. Convert each raw data into node data, because each node has:
a, child node, parent node: This is very important, because the indentation of each data, icon settings, whether to display, must be based on the father-son relationship between each data to judge the display;
b. Number of spaces in left margin: Set indentation to show the effect of tree structure
c. The state of deployment: Explain whether this node is currently deployed
2. When the adapter configures the View of the node data, it displays the data differently according to the attributes of the node data, so as to achieve the purpose of the display effect of the final tree structure.
After writing this demo, I deeply realized a truth:
Each control corresponds to one data, and the change of display state of the control is essentially the change of a parameter in the data it corresponds to.
Raw data Bean:
public class Bean {
@TreeId
int id;
@TreePid
int pid;
@TreeLabel
String name;
public Bean(int id, int pid, String name) {
this.id = id;
this.pid = pid;
this.name = name;
}
}
Node data:
public class Node {
public Node(int id, int pid, String name) {
this.id = id;
this.pid = pid;
this.name = name;
}
int id;
int pid;
String name;
/**
* Subnode
*/
List<Node> children = new ArrayList<>();
/**
* Parent node
*/
Node parent;
/**
* There are several units in front of them.
*/
int level;
/**
* Is it an unfolding state?
*/
boolean isExpand = false;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getPid() {
return pid;
}
public void setPid(int pid) {
this.pid = pid;
}
public List<Node> getChildren() {
return children;
}
public Node getParent() {
return parent;
}
public void setParent(Node parent) {
this.parent = parent;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getLevel() {
return level;
}
public void setLevel(int level) {
this.level = level;
}
public void setExpand(boolean expand) {
isExpand = expand;
}
}
Activity:
public class MainActivity extends Activity {
/**
* Raw data
*/
List<Bean> beans = new ArrayList<>();
/**
* Node data converted from raw data
*/
List<Node> nodes = new ArrayList<>();
/**
* Sorted node data
*/
List<Node> sortedNodes = new ArrayList<>();
/**
* Adapter
*/
TreeListViewAdapter adapter;
/**
* listview
*/
ListView lv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lv = (ListView) findViewById(R.id.lv);
//Initialize raw data
beans.add(new Bean(10, 7, "Northeasterners"));
beans.add(new Bean(4, 1, "people"));
beans.add(new Bean(12, 8, "Cantonese"));
beans.add(new Bean(2, 1, "Monkey"));
beans.add(new Bean(5, 2, "Golden Monkey"));
beans.add(new Bean(7, 4, "Northerners"));
beans.add(new Bean(3, 1, "Loong"));
beans.add(new Bean(1, 0, "Animal"));
beans.add(new Bean(9, 7, "Inner Mongolian"));
beans.add(new Bean(6, 2, "Macaque"));
beans.add(new Bean(11, 7, "Beijingers"));
beans.add(new Bean(8, 4, "Southerner"));
try {
//Transforming raw data into node data
nodes = TreeHelper.data2Node(beans);
//Sort node data
sortedNodes = TreeHelper.sort(nodes);
//Transfer sequenced node data to the adapter
adapter = new TreeListViewAdapter(this, sortedNodes);
//Display data
lv.setAdapter(adapter);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
TreeListViewAdapter:
public class TreeListViewAdapter extends BaseAdapter {
List<Node> datas;
Context context;
public TreeListViewAdapter(Context context, List<Node> datas) {
this.datas = datas;
this.context = context;
}
@Override
public int getCount() {
return datas.size();
}
@Override
public Object getItem(int i) {
return null;
}
@Override
public long getItemId(int i) {
return 0;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
final Node node = datas.get(i);
ViewHolder viewHolder;
if (view == null) {
view = LayoutInflater.from(context).inflate(R.layout.item, null);
viewHolder = new ViewHolder();
viewHolder.tv = (TextView) view.findViewById(R.id.tv);
viewHolder.iv = (ImageView) view.findViewById(R.id.iv);
view.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) view.getTag();
}
//display text
viewHolder.tv.setText(node.getName());
//When clicking on a node
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//If the current state of the node is expanded, then all its descendant nodes are set to closed state
if(node.isExpand==true){
TreeHelper.shutNode(node);
}
//Change the deployment state of the node to the opposite
node.setExpand(!node.isExpand);
//Refresh display
notifyDataSetChanged();
}
});
//If this node has children
if(node.children.size()>0){
//When the node state is expanded, set the corresponding icon
if(node.isExpand == true){
viewHolder.iv.setImageResource(R.drawable.tree_ec);
//When the node state is closed, set the corresponding icon
}else {
viewHolder.iv.setImageResource(R.drawable.tree_ex);
}
//If this node has no children, set the picture to null
}else {
viewHolder.iv.setImageBitmap(null);
}
//Set the left margin of this item
view.setPadding(node.getLevel()*50,0,0,0);
//If the node is the root node or its parent node is the expanded state, the node is displayed.
//Otherwise, this node is not displayed.
Node parentNode = node.getParent();
if (parentNode == null || parentNode.isExpand == true) {
return view;
} else{
return null;
}
}
class ViewHolder {
ImageView iv;
TextView tv;
}
}
TreeHelper:
public class TreeHelper {
/**
* Converting raw data to node data
* @param datas
* @return
* @throws IllegalAccessException
*/
public static List<Node> data2Node(List<Bean> datas) throws IllegalAccessException {
List<Node> nodes = new ArrayList<>();
Node node = null;
//Remove id, pid, name from the data source based on reflection
for (Bean t : datas) {
int id = -1;
int pid = -1;
String label = null;
Class<? extends Object> clazz = t.getClass();
Field[] fields = clazz.getDeclaredFields();
for (Field f : fields) {
if (f.getAnnotation(TreeId.class) != null) {
id = f.getInt(t);
}
if (f.getAnnotation(TreePid.class) != null) {
pid = f.getInt(t);
}
if (f.getAnnotation(TreeLabel.class) != null) {
label = (String) f.get(t);
}
if (id != -1 && pid != -1 && label != null) {
break;
}
}
node = new Node(id, pid, label);
nodes.add(node);
}
//Traverse through each node and subsequent nodes. There will be two situations.
// This node is the parent of a subsequent node
//This node is the child of a subsequent node
for (int i = 0; i < nodes.size(); i++) {
Node n = nodes.get(i);
for (int j = i + 1; j < nodes.size(); j++) {
Node m = nodes.get(j);
if (n.getId() == m.getPid()) {
n.getChildren().add(m);
m.setParent(n);
}
if (n.getPid() == m.getId()) {
n.setParent(m);
m.getChildren().add(n);
}
}
}
//Setting the left margin of this node should set several spaces
for (Node n : nodes) {
n.setLevel(calPadding(n,0));
}
return nodes;
}
/**
* Sort node data according to parent-child relationship
* @param nodes
* @return
*/
public static List<Node> sort(List<Node> nodes) {
//Select the root node first
List<Node> rootNodes = new ArrayList<>();
for (Node n : nodes) {
if (n.getParent() == null) {
rootNodes.add(n);
}
}
//In order to achieve the purpose of sorting, the nodes are put in one by one according to the parent-child relationship.
List<Node> sortedNodes = new ArrayList<>();
addNode(sortedNodes, rootNodes);
return sortedNodes;
}
/**
* Specific Implementation Method of Sorting Nodes
* @param sortedNodes
* @param rootNodes
*/
private static void addNode(List<Node> sortedNodes, List<Node> rootNodes) {
for (Node n : rootNodes) {
sortedNodes.add(n);
if (n.children.size() > 0) {
addNode(sortedNodes,n.children);
}
}
}
/**
* Set the expansion status of all child nodes of a node to close
* @param n
*/
public static void shutNode(Node n){
List<Node> children = n.getChildren();
if(children.size()>0){
for (Node n1 : children) {
n1.setExpand(false);
shutNode(n1);
}
}
}
/**
* Calculate the number of spaces on the left margin of this node
* @param node
* @param i
* @return
*/
public static int calPadding(Node node,int i){
if(node.parent!=null){
i++;
i=calPadding(node.parent,i);
}
return i;
}
}