The fastest Android TreeView appears!

Keywords: Android github less xml

The fastest Android TreeView appears!

Source address: https://github.com/niugao/RecyclerListTreeView

  • Based on RecyclerView.
  • The structure of storing data is not a Tree, but an ArrayList. Unlike all the known implementations on the Internet, it seems that people can't jump out of fixed thinking. You can compare the amount of code. This implementation is less than half of the others.
  • The core is a class representing Tree, but its essence is a List. There is no change to RecyclerView, only a small amount of encapsulation to Adapter, and users will not feel strange. That is to say, what you can do with RecyclerView is still possible.
  • Table tree in the form of List brings many benefits:
    - no recursion. All the places where recursion should be used become loops (Tree has no stack overflow no matter how many layers there are).
    - next is order. When inserting a node, you can specify that it is the father's son.
    – perfect for RecyclerView.
    – no different from List, both the root node and the child node correspond to a row in RecyclerView.
    – no changes to RecyclerView are required.

Poetry as evidence

It looks like a tree in the distance
It's not a tree
Like a tree, not a tree
It's for cattle

Example

Adapter:

public abstract class ListTreeAdapter<VH extends ListTreeViewHolder>
        extends RecyclerView.Adapter<VH> {

    protected ListTree tree;

    //Drawable resource id for expand and collapse icons
    private Bitmap expandIcon=null;
    private Bitmap collapseIcon=null;

    //Construction method
    public ListTreeAdapter(ListTree tree){
        this.tree=tree;

    }
    public ListTreeAdapter(ListTree tree,Bitmap expandIcon,Bitmap collapseIcon){
        this.tree=tree;

        this.expandIcon=expandIcon;
        this.collapseIcon=collapseIcon;
    }

    @Override
    final public VH onCreateViewHolder(ViewGroup parent, int viewType) {
        if(expandIcon==null){
            expandIcon=BitmapFactory.decodeResource(
                    parent.getContext().getResources(), R.drawable.expand);
        }

        if(collapseIcon==null){
            collapseIcon=BitmapFactory.decodeResource(
                    parent.getContext().getResources(),R.drawable.collapse);
        }

        LayoutInflater inflater = LayoutInflater.from(parent.getContext());
        ViewGroup container = (ViewGroup) inflater.inflate(
                R.layout.row_container_layout,parent,false);

        //To shrink or expand in response to a click event on Arrow
        ImageView arrowIcon = container.findViewById(R.id.listtree_arrowIcon);
        //Follow the width of the list control to calculate an appropriate size for it
        int w= parent.getMeasuredWidth();
        arrowIcon.getLayoutParams().width=w/15;
        arrowIcon.getLayoutParams().height=w/15;
        arrowIcon.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                ListTree.TreeNode node = (ListTree.TreeNode) v.getTag();
                if(node.isShowExpandIcon()) {
                    int nodePlaneIndex = tree.getNodePlaneIndex(node);
                    if (node.isExpand()) {
                        //Retract
                        int count = tree.collapseNode(nodePlaneIndex);
                        notifyItemChanged(nodePlaneIndex);
                        //Notify view to delete related lines
                        notifyItemRangeRemoved(nodePlaneIndex + 1, count);
                    } else {
                        //Open
                        int count = tree.expandNode(nodePlaneIndex);
                        notifyItemChanged(nodePlaneIndex);
                        //Notify view to insert related lines
                        notifyItemRangeInserted(nodePlaneIndex + 1, count);
                    }
                }
            }
        });

        //Subclass to create their own row view
        VH vh = onCreateNodeView(container,viewType);
        if(vh==null){
            return null;
        }
        vh.containerView = container;
        vh.arrowIcon=arrowIcon;
        vh.headSpace=container.findViewById(R.id.listtree_head_space);

        //container.addView(vh.itemView);
        return vh;
    }

    protected abstract VH onCreateNodeView(ViewGroup parent, int viewType);
    protected abstract void onBindNodeViewHolder(VH viewHoler,int position);

    @Override
    final public int getItemViewType(int position) {
        int count=0;
        ListTree.TreeNode node = tree.getNodeByPlaneIndex(position);
        return node.getLayoutResId();
    }

    @Override
    final public void onBindViewHolder(VH holder, int position) {
        //get node at the position
        ListTree.TreeNode node = tree.getNodeByPlaneIndex(position);
        if(node.isShowExpandIcon()) {
            if (node.isExpand()) {
                holder.arrowIcon.setImageBitmap(collapseIcon);
            } else {
                holder.arrowIcon.setImageBitmap(expandIcon);
            }
        }else{
            //No icon needed
            holder.arrowIcon.setImageBitmap(null);
        }

        holder.arrowIcon.setTag(node);

        //Change the indent distance according to the layer depth of node, starting from 0
        int layer = tree.getNodeLayerLevel(node);
        holder.headSpace.getLayoutParams().width=layer*20;

        //Give subclasses the opportunity to bind row data
        onBindNodeViewHolder(holder,position);
    }


    @Override
    final public int getItemCount() {
        return tree.size();
    }
}

Using Adapter

public class MainActivity extends AppCompatActivity {

    private ListTree tree=new ListTree();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });

        RecyclerView listView = findViewById(R.id.listview);

        //Create background data: a tree
        //Create groups. It's root node. All parent s are null
        ListTree.TreeNode groupNode1=tree.addNode(null,"Special care", R.layout.contacts_group_item);
        ListTree.TreeNode groupNode2=tree.addNode(null,"My friends", R.layout.contacts_group_item);
        ListTree.TreeNode groupNode3=tree.addNode(null,"Friend", R.layout.contacts_group_item);
        ListTree.TreeNode groupNode4=tree.addNode(null,"Family", R.layout.contacts_group_item);
        ListTree.TreeNode groupNode5=tree.addNode(null,"Classmate", R.layout.contacts_group_item);

        //The second floor
        ExampleListTreeAdapter.ContactInfo contact;
        Bitmap bitmap= BitmapFactory.decodeResource(getResources(), R.drawable.contacts_normal);
        contact = new ExampleListTreeAdapter.ContactInfo(
                bitmap,"WangTwo","[On-line]I'm Wang Er");
        ListTree.TreeNode contactNode1=tree.addNode(groupNode2,contact,R.layout.contacts_contact_item);
        ListTree.TreeNode contactNode2=tree.addNode(groupNode5,contact,R.layout.contacts_contact_item);
        //Add another
        bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.contacts_normal);
        contact=new ExampleListTreeAdapter.ContactInfo(bitmap,"Wang San","[Off-line]I'm not in shape");
        tree.addNode(groupNode2,contact,R.layout.contacts_contact_item);
        tree.addNode(groupNode5,contact,R.layout.contacts_contact_item);

        //Third floor
        bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.contacts_normal);
        contact=new ExampleListTreeAdapter.ContactInfo(bitmap,"East evil","[Off-line]Come out and make a counter-offer");
        ListTree.TreeNode n=tree.addNode(contactNode1,contact,R.layout.contacts_contact_item);
        n.setShowExpandIcon(false);
        //Add another
        bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.contacts_normal);
        contact=new ExampleListTreeAdapter.ContactInfo(bitmap,"Li Yuanyuan","[Off-line]I didn't go out yesterday");
        n=tree.addNode(contactNode1,contact,R.layout.contacts_contact_item);
        n.setShowExpandIcon(false);

        ExampleListTreeAdapter adapter=new ExampleListTreeAdapter(tree);
        listView.setLayoutManager(new LinearLayoutManager(this));
        listView.setAdapter(adapter);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}




Posted by daveoffy on Tue, 05 May 2020 07:40:35 -0700