随着公司自用app客户端功能&需求越来越复杂,某些页面的布局也越来越复杂。在前同事的建议下,使用RecyclerView来实现。

需求

大概需求如下图,需要通过登录用户的权限来展示这个表格布局。

IMG_0226

方案

  • 请求服务端登录接口,返回用户信息、角色信息、权限等
  • APP端根据权限组装数据传到Adapter
  • 渲染视图

实现

  • 在主页布局适合的布局添加以下布局代码

    <androidx.recyclerview.widget.RecyclerView
    android:id="@+id/workbench_recycleview"
    android:divider="#00000000"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/shape_bg"
    android:layout_marginLeft="15dp"
    android:layout_marginRight="15dp"
    android:layout_marginBottom="15dp">
    </androidx.recyclerview.widget.RecyclerView>
  • 定义item布局,代表每个item的布局样式等

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

    <LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:gravity="center_vertical"
    android:layout_marginTop="25dp"
    android:layout_marginLeft="15dp"
    android:layout_marginRight="15dp">

    <TextView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_weight="1"
    android:text="标题"
    android:id="@+id/wb_menu_txt_title"
    android:textSize="16sp"
    android:textStyle="bold"
    android:textColor="#555555"/>

    <ImageView
    android:layout_width="36dp"
    android:layout_height="36dp"
    android:id="@+id/wb_menu_img_title"
    android:src="@mipmap/wk_ck"/>
    </LinearLayout>

    <LinearLayout
    android:layout_width="match_parent"
    android:layout_height="20dp"
    android:orientation="vertical"
    android:layout_marginBottom="25dp"
    android:layout_marginLeft="15dp"
    android:layout_marginRight="15dp">

    <TextView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:text="这是一段说明"
    android:id="@+id/wb_menu_txt_info"
    android:textSize="14sp"
    android:textColor="#999999"/>
    </LinearLayout>

    </LinearLayout>

    预览效果如下

    image-20210917204125464

  • 定义Holder类,继承RecyclerView.ViewHolder

    public class WorkBenchItemViewHolder extends RecyclerView.ViewHolder {

    private final TextView txtTitle;
    private final TextView txtInfo;
    private final ImageView imgTitle;

    public WorkBenchItemViewHolder(View view){
    super(view);
    txtTitle = view.findViewById(R.id.wb_menu_txt_title);
    txtInfo = view.findViewById(R.id.wb_menu_txt_info);
    imgTitle = view.findViewById(R.id.wb_menu_img_title);
    }

    public TextView getTxtInfo(){
    return this.txtInfo;
    }

    public ImageView getImg(){
    return this.imgTitle;
    }

    public TextView getTxtTitle(){
    return txtTitle;
    }
    }

  • 定义Adapter类,继承RecyclerView.Adapter<WorkBenchItemViewHolder>

    public class WorkBenchItemViewAdapter extends RecyclerView.Adapter<WorkBenchItemViewHolder> {

    public List<WorkbenchMenuBean> mDatas;
    private final Context mContext;
    private OnItemClickListener listener;

    public WorkBenchItemViewAdapter(Context context, List<WorkbenchMenuBean> datas) {
    this.mContext = context;
    this.mDatas = datas;
    }

    @NonNull
    @Override
    public WorkBenchItemViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    return new WorkBenchItemViewHolder(LayoutInflater.from(mContext).inflate(R.layout.home_workbench_item_view, parent,
    false));
    }

    @Override
    public void onBindViewHolder(WorkBenchItemViewHolder holder, final int position) {
    holder.getTxtTitle().setText(mDatas.get(position).getTxtTitle());
    holder.getTxtInfo().setText(mDatas.get(position).getTxtInfo());
    holder.getImg().setImageResource(mDatas.get(position).getImgTitle());

    if (listener != null) {
    holder.itemView.setOnClickListener(view -> listener.onItemClick(view, position));
    }
    }

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

    //第二步, 写一个公共的方法
    public void setOnItemClickListener(OnItemClickListener listener) {
    this.listener = listener;
    }

    public interface OnItemClickListener {
    void onItemClick(View view, int position);
    }

    }
  • 在对应的页面初始化页面逻辑处添加处理逻辑

    定义相关属性

    private RecyclerView recyclerView;
    private WorkBenchItemViewAdapter adapter;
    private List<WorkbenchMenuBean> listData = new ArrayList<>();

    定义获取列表的方法

    // 通过登录后获取的角色判断

    // 这里展示如果是超级账号的情况
    boolean superAccount = loginInfo.isSuperAccount();
    if (superAccount) {
    listData.add(new WorkbenchMenuBean("pb", "功能1", "功能1描述", R.mipmap.wk_pb));
    listData.add(new WorkbenchMenuBean("zj", "功能2", "。。。", R.mipmap.wk_zj));
    listData.add(new WorkbenchMenuBean("sc", "功能3", "。。。", R.mipmap.wk_sc));
    listData.add(new WorkbenchMenuBean("ck", "功能4", "。。。", R.mipmap.wk_ck));
    listData.add(new WorkbenchMenuBean("sk", "功能5", "。。。", R.mipmap.wk_sk));
    return;
    }

    这里更好的处理方法是这些data也通过服务端返回,客户端只管处理

    调用recyclerView的其他api

    // 设置LayoutManager
    recyclerView.setLayoutManager(new GridLayoutManager(getContext(), 2));
    recyclerView.addItemDecoration(new CommonDecoration(Objects.requireNonNull(getContext())));

    adapter = new WorkBenchItemViewAdapter(getContext(), listData);

    // 设置点击事件
    adapter.setOnItemClickListener((view, position) -> {
    WorkbenchMenuBean workbenchMenuBean = adapter.mDatas.get(position);
    onWorkbenchMenuItemClick(workbenchMenuBean);
    });
    recyclerView.setAdapter(adapter);

常用方法

1、获取recyclerView内容高度

// 获取recyclerView内容高度
int recyclerViewRealHeight = recyclerView.computeVerticalScrollRange();

我们通过recyclerView.getHeight方法获取到的高度是RecyclerView控件的高度,不是内容高度

2、获取adapter中的item总个数

int size = recyclerView.getAdapter().getItemCount();

3、获取recyclerView可见的item数量

int childCount = recyclerView.getChildCount();

4、获取某个Item的实际position

RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
//获取其在adapter中的位置
int position = params.getViewLayoutPosition();

// 这个方式也可以
int position = recyclerView.getChildAdapterPosition(view);

5、根据position获取对应的Item的View,需要注意的是,如果当前position对应的View不可见,获取到的View为null。

// llm为对应的LayoutManager
View itemView = llm.findViewByPosition(position);

6、获取第一个可见的Item的position

int firstPosition = ((LinearLayoutManager)recyclerView.getLayoutManager()).findFirstVisibleItemPosition();

// 这样也可以获取到
View childFirst = recyclerView.getChildAt(0);
RecyclerView.LayoutParams paramsFirst = (RecyclerView.LayoutParams) childFirst.getLayoutParams();
int firstPosition1 = paramsFirst.getViewLayoutPosition();

7、获取第一个完全可见的Item的position

int firstCompletelyVisibleItemPosition = ((LinearLayoutManager)recyclerView.getLayoutManager()).findFirstCompletelyVisibleItemPosition();

8、获取最后一个可见的Item的position

int lastPosition = ((LinearLayoutManager)recyclerView.getLayoutManager()).findLastVisibleItemPosition();

// 这样也可以获取到
int childCount = recyclerView.getChildCount();
View childLast = recyclerView.getChildAt(childCount - 1);
RecyclerView.LayoutParams paramsLast = (RecyclerView.LayoutParams) childLast.getLayoutParams();
int lastPosition1 = paramsLast.getViewLayoutPosition();

9、获取最后一个完全可见的Item的position

int lastCompletelyVisibleItemPosition = ((LinearLayoutManager)parent.getLayoutManager()