RecyclerView 分层级展示(抽屉) TreeView

先看效果

难点:  数据层级的划分;理清楚层级关系, 剩下的就简单明了了;

1. 第一步 new Adapter, and setAdapter; (不需要setLayoutManager, Adapter里有set);

mAdapter = new TreeViewAdapter(getContext(),mRecyclerView);
mRecyclerView.setAdapter(mAdapter);

2. 第二步, 划分数据层级;(不好说, 自己看代码理解)

注意点: CommonMenu的构造方法中初始化层级, 是否展开;

CommonMenu 就是菜单, 菜单中也可能包含菜单, 具体是包含还是并列同级, 取决于Level_等级;

0~3都是菜单, LEVEL_ITEM 为具体对象;

Set数据过程 以及需要的实体类 如下:(具体对象的实体类就贴了一个KaKou, 其他的类似, 继承BaseMenu即可)

            //初始化 Adapter需要的数据mBaseList 
            List<BaseMenu> mBaseList = new ArrayList<>();

            for (int i = 0; i < 2; i++) {
                CommonMenu lcMenu = new CommonMenu(BaseMenu.LEVEL_1, false);
                lcMenu.setName("林场" + i);

                List<BaseMenu> lcChildList = new ArrayList<>();
                lcMenu.setChild(lcChildList);

                CommonMenu yunTaiMenu = new CommonMenu(BaseMenu.LEVEL_2, false);
                yunTaiMenu.setName("云台");
                lcChildList.add(yunTaiMenu);

                List<BaseMenu> ytChildList = new ArrayList<>();
                for (int j = 0; j < 2; j++) {
                    YunTai item = new YunTai();
                    item.setName("云台Name" + j);
                    ytChildList.add(item);
                }
                yunTaiMenu.setChild(ytChildList);

                CommonMenu kkMenu = new CommonMenu(BaseMenu.LEVEL_2, false);
                kkMenu.setName("卡口");
                lcChildList.add(kkMenu);

                List<BaseMenu> kkChildList = new ArrayList<>();
                for (int j = 0; j < 2; j++) {
                    KaKou item = new KaKou();
                    item.setName("卡口Name" + j);
                    kkChildList.add(item);
                }
                kkMenu.setChild(kkChildList);

                CommonMenu fdMenu = new CommonMenu(BaseMenu.LEVEL_2, false);
                fdMenu.setName("防盗");
                lcChildList.add(fdMenu);

                List<BaseMenu> fdChildList = new ArrayList<>();
                for (int j = 0; j < 2; j++) {
                    FangDao item = new FangDao();
                    item.setName("防盗Name" + j);
                    fdChildList.add(item);
                }
                fdMenu.setChild(fdChildList);

                CommonMenu qxzMenu = new CommonMenu(BaseMenu.LEVEL_2, false);
                qxzMenu.setName("气象站");
                lcChildList.add(qxzMenu);

                List<BaseMenu> qxzChildList = new ArrayList<>();
                for (int j = 0; j < 2; j++) {
                    QiXiangZhan item = new QiXiangZhan();
                    item.setName("气象站Name" + j);
                    qxzChildList.add(item);
                }
                qxzMenu.setChild(qxzChildList);


                mBaseList.add(lcMenu);
            }

            mAdapter.setBaseList(mBaseList);
            mAdapter.notifyDataSetChanged();

public abstract class BaseMenu {

    public static final int LEVEL_0 = 0;//林局
    public static final int LEVEL_1 = 1;//林场
    public static final int LEVEL_2 = 2;//云台
    public static final int LEVEL_3 = 3;//备用-管护站
    public static final int LEVEL_ITEM = 4;//具体设备

    protected String name;
    protected int level = LEVEL_ITEM;
    protected boolean expand = true;

    public boolean isExpand() {
        return expand;
    }

    public void setExpand(boolean expand) {
        this.expand = expand;
    }

    public int getLevel() {
        return level;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public boolean isItem(){
        return level == LEVEL_ITEM;
    }

    public abstract List<BaseMenu> getChild();

}
public class CommonMenu extends BaseMenu {

    private List<BaseMenu> child;

    public List<BaseMenu> getChild() {
        return child;
    }

    public void setChild(List<BaseMenu> child) {
        this.child = child;
    }

    public CommonMenu(int level, boolean expand) {
        this.level = level;
        this.expand = expand;
    }
}
public class KaKou extends BaseMenu{

    private String uuid;
    private String name;
    private String lon;
    private String lat;

    public String getUuid() {
        return uuid;
    }

    public void setUuid(String uuid) {
        this.uuid = uuid;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public List<BaseMenu> getChild() {
        return null;
    }

    public String getLon() {
        return lon;
    }

    public void setLon(String lon) {
        this.lon = lon;
    }

    public String getLat() {
        return lat;
    }

    public void setLat(String lat) {
        this.lat = lat;
    }
}

3. 第三步 愉快的复制粘贴过程(Adapter, 以及 布局)


import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import com.sxwy.fanghuo.R;
import com.sxwy.fanghuo.data.BaseMenu;

import java.util.ArrayList;
import java.util.List;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

/**
 * Created by ZhouWengong on 2023/5/17.
 */
public class TreeViewAdapter extends RecyclerView.Adapter<ViewHolder> {
    public static final String TAG = TreeViewAdapter.class.getSimpleName();
    private LinearLayoutManager layoutManager;

    private final List<BaseMenu> mCurrentList;//当前展示的数据
    private Context mContext;

    private RecyclerView mRecyclerView;

    public TreeViewAdapter(Context context, RecyclerView recyclerView) {
        mContext = context;
        mCurrentList = new ArrayList<>();
        if (recyclerView != null) {
            mRecyclerView = recyclerView;
            layoutManager = new LinearLayoutManager(context);
            mRecyclerView.setLayoutManager(layoutManager);

            //展开与关闭时的动画耗时;
            RecyclerView.ItemAnimator itemAnimator = recyclerView.getItemAnimator();
            if (itemAnimator != null) {
                int duration = 10;
                itemAnimator.setAddDuration(duration);
                itemAnimator.setRemoveDuration(duration);
            }
        }
    }

    public void setBaseList(List<BaseMenu> baseList) {
        if (baseList != null) {
            initCurrentMenu(baseList);
        }
    }

    private void initCurrentMenu(List<BaseMenu> baseMenus) {
        for (BaseMenu baseMenu : baseMenus) {
            mCurrentList.add(baseMenu);
            if (!baseMenu.isItem()) {
                if (baseMenu.getChild() != null && baseMenu.isExpand()) {
                    initCurrentMenu(baseMenu.getChild());
                }
            }
        }
    }

    private void onMenuExpand(BaseMenu baseMenu, int position) {
        if (baseMenu.getChild() != null) {
            int size = mCurrentList.size();

            if (baseMenu.isExpand()) {
                int lastVisibleItemPosition = layoutManager.findLastVisibleItemPosition();

                insertMenuChild(baseMenu, position + 1);

                int itemCount = mCurrentList.size() - size;
                notifyItemRangeInserted(position + 1, itemCount);
                notifyItemRangeChanged(position, mCurrentList.size());

                int toPosition = position + itemCount;


                if (lastVisibleItemPosition < toPosition) {
                    mRecyclerView.scrollToPosition(toPosition);
                }
            } else {
                removeMenuChild(baseMenu);
                notifyItemRangeRemoved(position + 1, size - mCurrentList.size());
                notifyItemRangeChanged(position, mCurrentList.size());
            }
        } else {
            notifyItemChanged(position);
        }
    }

    private void insertMenuChild(BaseMenu menu, int position) {
        if (menu.isExpand()) {
            List<BaseMenu> child = menu.getChild();
            if (child != null) {
//                for (BaseMenu baseMenu : child) {//child逆序添加,因为position固定;
//                    mCurrentList.add(position , baseMenu);
//                    if (!baseMenu.isItem() && baseMenu.isExpand()) {
//                        insertMenuChild(baseMenu, position + 1);
//                    }
//                }
                for (int i = child.size() - 1; i >= 0; i--) {//逆序遍历, 正序添加
                    BaseMenu baseMenu = child.get(i);
                    mCurrentList.add(position, baseMenu);
                    if (!baseMenu.isItem() && baseMenu.isExpand()) {
                        insertMenuChild(baseMenu, position + 1);
                    }
                }

            }
        }
    }

    private void removeMenuChild(BaseMenu menu) {
        List<BaseMenu> child = menu.getChild();
        if (child != null) {
            mCurrentList.removeAll(child);
            for (BaseMenu baseMenu : child) {
                removeMenuChild(baseMenu);
            }
        }
    }


    public int getLayoutId(int viewType) {
        int ret = 0;
        switch (viewType) {
            case BaseMenu.LEVEL_0:
                break;
            case BaseMenu.LEVEL_1:
                ret = R.layout.item_treeview_menu_1;
                break;
            case BaseMenu.LEVEL_2:
                ret = R.layout.item_treeview_menu_2;
                break;
            case BaseMenu.LEVEL_3:
                break;
            case BaseMenu.LEVEL_ITEM:
                ret = R.layout.item_treeview_menu_item;
                break;
        }

        return ret;
    }

    @Override
    public int getItemViewType(int position) {
        return mCurrentList.get(position).getLevel();
    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        return ViewHolder.getViewHolder(mContext, parent, getLayoutId(viewType));
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        BaseMenu baseMenu = mCurrentList.get(position);
        ((TextView) holder.getView(R.id.text)).setText(baseMenu.getName());
        if (!baseMenu.isItem()) {//我的图片资源箭头是朝右的,根据实际情况修改即可
            holder.getView(R.id.indicator).setRotation(baseMenu.isExpand() ? 90 : 270);
        }
        View holderView = holder.getView(R.id.parent);
        holderView.setTag(position);
        holderView.setOnClickListener(onClickListener);

    }

    private final View.OnClickListener onClickListener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            int position = (int) v.getTag();
            BaseMenu baseMenu = mCurrentList.get(position);
            if (!baseMenu.isItem()) {
                baseMenu.setExpand(!baseMenu.isExpand());
                onMenuExpand(baseMenu, position);
            }else {
                //todo item点击时触发
            }
        }
    };

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

}

布局只传了一个, 根据情况复制粘贴就可以,

注意: 每个Level 对应一个布局, 每个布局的paddingStart应该设置合理的间距(@dimen/treeViewMarginLevel_1)

item_treeview_menu_1.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/parent"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="center"
    android:orientation="vertical">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="60dp"
        android:background="@drawable/shape_white_radius_5"
        android:gravity="center_vertical"
        android:paddingStart="@dimen/treeViewMarginLevel_1">

        <ImageView
            android:id="@+id/headPic"
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:layout_marginStart="10dp"
            android:layout_marginEnd="10dp"
            android:src="@mipmap/ic_cf_icon" />


        <TextView
            android:id="@+id/text"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="名字"
            android:textColor="@color/text_black"
            android:textSize="14sp"
            android:textStyle="bold" />


        <ImageView
            android:id="@+id/indicator"
            android:layout_width="15dp"
            android:layout_height="15dp"
            android:layout_marginStart="20dp"
            android:layout_marginEnd="10dp"
            android:rotation="90"
            android:src="@mipmap/ic_next_page_indicator"
            android:visibility="visible" />
    </LinearLayout>

    <View
        android:layout_width="0dp"
        android:layout_height="1dp" />


</LinearLayout>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值