android Tree Structure Navigation Map

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;
    }
}

Posted by Aus on Sun, 14 Jul 2019 13:05:24 -0700