最快的Android TreeView出现了!

最快的Android TreeView出现了!

源码地址:https://github.com/niugao/RecyclerListTreeView

  • 基于RecyclerView实现。
  • 存储数据的结构并不是Tree,而是一个ArrayList。与所有已知的网上的实现都不一样,大家似乎都跳不出固定思维。 可以比较一下代码量,此实现比其它的少一半都不止。
  • 核心是一个表示Tree的类,但它的本质是一个List。对RecyclerView没有任何改动,对Adapter只有少量封装, 使用者不会产生任何陌生感。也就是说你对RecyclerView能做的,现在依然能做。
  • 以List的形式表式树,带来很多好处:
    – 没有了递归。该用递归的地方全部变成了循环(Tree不论有多少层都没有栈溢出)。
    – 其次是有序,插入节点时,可以指定它是它爸爸的第几个儿子。
    – 极其适合在RecyclerView中使用。
    – 跟List无异,无论根节点还是子节点都对应RecyclerView中的一行。
    – 不需对RecyclerView做任何改动。

有诗为证

远看像棵树
近看不是树
似树而非树
是为牛逼树

##示例

在Gradle中添加依赖:

implementation ‘com.edu:recyclerlisttreeview:0.1.4’

定义Adapter:

public class ExampleListTreeAdapter extends
        ListTreeAdapter<ExampleListTreeAdapter.BaseViewHolder> {

    //行上弹出菜单的侦听器
    private PopupMenu.OnMenuItemClickListener itemMenuClickListener;
    //记录弹出菜单是在哪个行上出现的
    private ListTree.TreeNode currentNode;

    //保存子行信息的类
    public static class ContactInfo{
        //头像,用于设置给ImageView。
        private Bitmap bitmap;
        //标题
        private String title;
        //描述
        private String detail;

        public ContactInfo(Bitmap bitmap, String title, String detail) {
            this.bitmap = bitmap;
            this.title = title;
            this.detail = detail;
        }

        public Bitmap getBitmap() {
            return bitmap;
        }

        public String getTitle() {
            return title;
        }

        public String getDetail() {
            return detail;
        }
    }

    //构造方法
    public ExampleListTreeAdapter(ListTree tree,
                                  PopupMenu.OnMenuItemClickListener listener){
        super(tree);
        this.itemMenuClickListener=listener;
    }

    public ListTree.TreeNode getCurrentNode() {
        return currentNode;
    }

    @Override
    protected BaseViewHolder onCreateNodeView(ViewGroup parent, int viewType){
        LayoutInflater inflater = LayoutInflater.from(parent.getContext());

        //创建不同的行View
        if(viewType==R.layout.contacts_group_item){
            //注意!此处有一个不同!最后一个参数必须传true!
            View view = inflater.inflate(viewType,parent,true);
            //用不同的ViewHolder包装
            return new GroupViewHolder(view);
        }else if(viewType == R.layout.contacts_contact_item){
            //注意!此处有一个不同!最后一个参数必须传true!
            View view = inflater.inflate(viewType,parent,true);
            //用不同的ViewHolder包装
            return  new ContactViewHolder(view);
        }else{
            return null;
        }
    }

    @Override
    protected void onBindNodeViewHolder(BaseViewHolder holder, int position) {
        View view = holder.itemView;
        //get node at the position
        ListTree.TreeNode node = tree.getNodeByPlaneIndex(position);

        if(node.getLayoutResId() == R.layout.contacts_group_item){
            //group node
            String title = (String)node.getData();

            GroupViewHolder gvh= (GroupViewHolder) holder;
            gvh.textViewTitle.setText(title);
            gvh.textViewCount.setText("0/"+node.getChildrenCount());
            gvh.aSwitch.setChecked(node.isChecked());
        }else if(node.getLayoutResId() == R.layout.contacts_contact_item){
            //child node
            ContactInfo info = (ContactInfo) node.getData();

            ContactViewHolder cvh= (ContactViewHolder) holder;
            cvh.imageViewHead.setImageBitmap(info.getBitmap());
            cvh.textViewTitle.setText(info.getTitle());
            cvh.textViewDetail.setText(info.getDetail());
            cvh.aSwitch.setChecked(node.isChecked());
        }
    }

    //组行和联系人行的Holder基类
    class BaseViewHolder extends ListTreeAdapter.ListTreeViewHolder{
        public BaseViewHolder(View itemView) {
            super(itemView);
        }
    }

    //将ViewHolder声明为Adapter的内部类,反正外面也用不到
    class GroupViewHolder extends BaseViewHolder {

        TextView textViewTitle;
        TextView textViewCount;
        Switch aSwitch;
        TextView textViewMenu;

        public GroupViewHolder(View itemView) {
            super(itemView);

            textViewTitle = itemView.findViewById(R.id.textViewTitle);
            textViewCount = itemView.findViewById(R.id.textViewCount);
            aSwitch = itemView.findViewById(R.id.switchChecked);
            textViewMenu = itemView.findViewById(R.id.textViewMenu);

            //应响应点击事件而不是CheckedChange事件,因为那样会引起事件的递归触发
            aSwitch.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    int planeIndex = getAdapterPosition();
                    ListTree.TreeNode node = tree.getNodeByPlaneIndex(planeIndex);
                    node.setChecked(!node.isChecked());
                    //改变所有的子孙们的状态
                    int count =tree.setDescendantChecked(planeIndex,node.isChecked());
                    notifyItemRangeChanged(planeIndex,count+1);
                }
            });

            //点了PopMenu控件,弹出PopMenu
            textViewMenu.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    int nodePlaneIndex = getAdapterPosition();
                    ListTree.TreeNode node = tree.getNodeByPlaneIndex(nodePlaneIndex);
                    currentNode=node;
                    PopupMenu popup = new PopupMenu(v.getContext(), v);
                    popup.setOnMenuItemClickListener(itemMenuClickListener);
                    MenuInflater inflater = popup.getMenuInflater();
                    inflater.inflate(R.menu.menu_item, popup.getMenu());
                    popup.show();
                }
            });
        }
    }

    class ContactViewHolder extends BaseViewHolder{
        ImageView imageViewHead;
        TextView textViewTitle;
        TextView textViewDetail;
        Switch aSwitch;

        public ContactViewHolder(View itemView) {
            super(itemView);

            imageViewHead = itemView.findViewById(R.id.imageViewHead);
            textViewTitle = itemView.findViewById(R.id.textViewTitle);
            textViewDetail = itemView.findViewById(R.id.textViewDetail);
            aSwitch = itemView.findViewById(R.id.switchChecked);

            //应响应点击事件而不是CheckedChange事件,因为那样会引起事件的递归触发
            aSwitch.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    int nodePlaneIndex = getAdapterPosition();
                    ListTree.TreeNode node = tree.getNodeByPlaneIndex(nodePlaneIndex);
                    node.setChecked(!node.isChecked());
                    //改变所有的子孙们的状态
                    int count =tree.setDescendantChecked(nodePlaneIndex,node.isChecked());
                    notifyItemRangeChanged(nodePlaneIndex,count+1);
                }
            });
        }
    }
}

###使用Adapter

public class MainActivity extends AppCompatActivity
        implements PopupMenu.OnMenuItemClickListener {

    //保存数据的集合
    private ListTree tree=new ListTree();
    //从ListTreeAdapter派生的Adapter
    ExampleListTreeAdapter adapter;

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

        //使用Android原生的RecyclerView即可
        RecyclerView listView = findViewById(R.id.listview);

        //创建后台数据:一棵树
        //创建组们,是root node,所有parent为null
        ListTree.TreeNode groupNode1=tree.addNode(null,"特别关心", R.layout.contacts_group_item);
        ListTree.TreeNode groupNode2=tree.addNode(null,"我的好友", R.layout.contacts_group_item);
        ListTree.TreeNode groupNode3=tree.addNode(null,"朋友", R.layout.contacts_group_item);
        ListTree.TreeNode groupNode4=tree.addNode(null,"家人", R.layout.contacts_group_item);
        ListTree.TreeNode groupNode5=tree.addNode(null,"同学", R.layout.contacts_group_item);

        //第二层
        ExampleListTreeAdapter.ContactInfo contact;
        Bitmap bitmap= BitmapFactory.decodeResource(getResources(), R.drawable.contacts_normal);
        contact = new ExampleListTreeAdapter.ContactInfo(bitmap,"王二","[在线]我是王二");
        ListTree.TreeNode contactNode1=tree.addNode(groupNode2,contact,R.layout.contacts_contact_item);
        ListTree.TreeNode contactNode2=tree.addNode(groupNode5,contact,R.layout.contacts_contact_item);
        //再添加一个
        bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.contacts_normal);
        contact=new ExampleListTreeAdapter.ContactInfo(bitmap,"王三","[离线]我没有状态");
        tree.addNode(groupNode2,contact,R.layout.contacts_contact_item);
        tree.addNode(groupNode5,contact,R.layout.contacts_contact_item);

        //第三层
        bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.contacts_normal);
        contact=new ExampleListTreeAdapter.ContactInfo(bitmap,"东邪","[离线]出来还价");
        ListTree.TreeNode n=tree.addNode(contactNode1,contact,R.layout.contacts_contact_item);
        n.setShowExpandIcon(false);
        //再添加一个
        bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.contacts_normal);
        contact=new ExampleListTreeAdapter.ContactInfo(bitmap,"李圆圆","[离线]昨天出门没出去");
        n=tree.addNode(contactNode1,contact,R.layout.contacts_contact_item);
        n.setShowExpandIcon(false);

        adapter=new ExampleListTreeAdapter(tree,this);
        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) {
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if(id == R.id.action_del_selected){
            //删除选中的Nodes,删一个Node时会将其子孙一起删掉
            tree.removeCheckedNodes();
            adapter.notifyDataSetChanged();
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    //响应某个Node上的快捷菜单的选择事件
    @Override
    public boolean onMenuItemClick(MenuItem item){
        switch (item.getItemId()) {
            case R.id.action_add_item:
                //向当前行增加一个儿子
                ListTree.TreeNode node = adapter.getCurrentNode();
                Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.contacts_normal);
                ExampleListTreeAdapter.ContactInfo contact=new ExampleListTreeAdapter.ContactInfo(
                        bitmap,"New contact","[离线]我没有状态");
                ListTree.TreeNode childNode = tree.addNode(node,contact,R.layout.contacts_contact_item);
                adapter.notifyTreeItemInserted(node,childNode);
                return true;
            case R.id.action_clear_children:
                //清空所有的儿子们
                node = adapter.getCurrentNode();
                Pair<Integer,Integer> range = tree.clearDescendant(node);
                adapter.notifyItemRangeRemoved(range.first,range.second);
                return true;
            default:
                return false;
        }
    }
}

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

猜你喜欢

转载自blog.csdn.net/nkmnkm/article/details/78985540