最快的Android TreeView出现了!

最快的Android TreeView出现了!

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

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

有诗为证

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

示例

在Gradle中添加依赖:

compile ‘com.niuedu:recyclerlisttreeview:0.1.0’

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){
        View view = null;
        LayoutInflater inflater = LayoutInflater.from(parent.getContext());
        BaseViewHolder vh;
        //创建不同的行View
        if(viewType==R.layout.contacts_group_item){
            //最后一个参数必须传true
            view = inflater.inflate(viewType,parent,true);
            vh=new GroupViewHolder(view);
        }else if(viewType == R.layout.contacts_contact_item){
            view = inflater.inflate(viewType,parent,true);
            vh=new ContactViewHolder(view);
        }else{
            return null;
        }

        return vh;

    }

    @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());

            gvh.aSwitch.setTag(node);
            gvh.textViewMenu.setTag(node);
        }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());

            cvh.aSwitch.setTag(node);
        }
    }

    //组行和联系人行的Holder基类
    class BaseViewHolder extends 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) {
                    ListTree.TreeNode node = (ListTree.TreeNode) view.getTag();
                    node.setChecked(!node.isChecked());
                    int planeIndex = tree.getNodePlaneIndex(node);
                    //改变所有的子孙们的状态
                    int count =tree.setDescendantChecked(planeIndex,node.isChecked());
                    notifyItemRangeChanged(planeIndex,count+1);
                }
            });

            //点了PopMenu控件,弹出PopMenu
            textViewMenu.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    ListTree.TreeNode node = (ListTree.TreeNode) v.getTag();
                    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) {
                    ListTree.TreeNode node = (ListTree.TreeNode) view.getTag();
                    node.setChecked(!node.isChecked());
                    int planeIndex = tree.getNodePlaneIndex(node);
                    //改变所有的子孙们的状态
                    int count =tree.setDescendantChecked(planeIndex,node.isChecked());
                    notifyItemRangeChanged(planeIndex,count+1);
                }
            });
        }
    }
}
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180

使用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_settings) {
            return true;
        }else if(id == R.id.action_del_selected){
            //删除选中的Nodes,删一个Node时会将其子孙一起删掉
            tree.removeCheckedNodes();
            adapter.notifyDataSetChanged();
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    @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;
            default:
                return false;
        }
    }
}

   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96

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

转自:http://blog.csdn.net/niu_gao/article/details/78985540

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值