一、使用情景分析
在有些时候,我们需要嵌套使用RecyclerView才能恰当的构建布局,比如在下方的墨刀项目中,对于购物车界面就需要使用RecyclerView进行嵌套。
游戏交易平台项目中的购物界面,首先为保证底栏,上方内容都放置于Fragment中,中间区域的商店利用RecyclerView进行加载。
外层布局分析
外层为商店信息,主要有以下控件需要根据数据动态加载:
信息 | 控件 |
---|---|
商店复选框 | CheckBox |
店铺图标 | imageView |
店铺名称 | TextView |
商品数据 | RecyclerView |
内层布局分析
内层为用户添加的要购买的商品信息,主要有以下控件需要动态加载:
信息 | 控件 |
---|---|
货品复选框 | CheckBox |
货品图片 | ImageView |
货品标题 | TextView |
发货方式 | TextView |
货品单价 | TextView |
数量 | TextView组合 |
二、布局代码
布局不是本文重点,参考下方代码即可,不过多赘述。
外层布局代码
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:padding="10dp"
app:cardCornerRadius="10dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<CheckBox
android:id="@+id/shopCheckBox"
style="@style/Widget.AppCompat.CompoundButton.RadioButton"
android:layout_width="30dp"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/imageView30"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_marginStart="8dp"
app:layout_constraintBottom_toBottomOf="@+id/shopCheckBox"
app:layout_constraintStart_toEndOf="@+id/shopCheckBox"
app:layout_constraintTop_toTopOf="@+id/shopCheckBox"
app:srcCompat="@drawable/shopcar_shop_icon" />
<TextView
android:id="@+id/shopname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:text="TextView"
app:layout_constraintBottom_toBottomOf="@+id/imageView30"
app:layout_constraintStart_toEndOf="@+id/imageView30"
app:layout_constraintTop_toTopOf="@+id/imageView30" />
<ImageView
android:id="@+id/imageView31"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginStart="8dp"
app:layout_constraintBottom_toBottomOf="@+id/shopname"
app:layout_constraintStart_toEndOf="@+id/shopname"
app:layout_constraintTop_toTopOf="@+id/shopname"
app:srcCompat="@drawable/right_arrow" />
<TextView
android:id="@+id/textView46"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/theme_gray"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/shopCheckBox" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/shopGoodRecyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView46" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
内层布局代码
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<CheckBox
android:id="@+id/ShopCarGoodCheckBox"
style="@style/Widget.AppCompat.CompoundButton.RadioButton"
android:layout_width="30dp"
android:layout_height="60dp"
android:clickable="true"
app:layout_constraintBottom_toBottomOf="@+id/ShopCarGoodImg"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/ShopCarGoodImg" />
<ImageView
android:id="@+id/ShopCarGoodImg"
android:layout_width="60dp"
android:layout_height="60dp"
app:layout_constraintStart_toEndOf="@+id/ShopCarGoodCheckBox"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/goods_gameitem" />
<TextView
android:id="@+id/ShopCarGoodTitle"
android:layout_width="212dp"
android:layout_height="40dp"
android:layout_marginStart="16dp"
android:text="TextView"
app:layout_constraintStart_toEndOf="@+id/ShopCarGoodImg"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/ShopCarGoodShippingForm"
android:layout_width="108dp"
android:layout_height="16dp"
android:text="TextView"
android:textColor="@color/text_gray"
android:textSize="12sp"
app:layout_constraintStart_toStartOf="@+id/ShopCarGoodTitle"
app:layout_constraintTop_toBottomOf="@+id/ShopCarGoodTitle" />
<TextView
android:id="@+id/ShopCarGoodPrice"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="TextView"
android:textColor="@color/theme_red"
android:textSize="16sp"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="@+id/ShopCarGoodShippingForm"
app:layout_constraintTop_toBottomOf="@+id/ShopCarGoodShippingForm" />
<com.dreamgyf.android.ui.widget.shape.ShapeLayout
android:layout_width="78dp"
android:layout_height="22dp"
app:cornerRadius="4dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/ShopCarGoodPrice"
app:strokeColor="@color/text_light_gray"
app:strokeWidth="1dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.dreamgyf.android.ui.widget.shape.ShapeLayout
android:layout_width="22dp"
android:layout_height="match_parent"
app:cornerBottomLeftRadius="4dp"
app:cornerTopLeftRadius="4dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:strokeColor="@color/text_light_gray"
app:strokeWidth="1dp">
<TextView
android:id="@+id/textView40"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="-" />
</com.dreamgyf.android.ui.widget.shape.ShapeLayout>
<TextView
android:id="@+id/ShopCarGoodNumbers"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="22dp"
android:layout_marginEnd="22dp"
android:gravity="center"
android:text="0"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<com.dreamgyf.android.ui.widget.shape.ShapeLayout
android:layout_width="22dp"
android:layout_height="match_parent"
app:cornerBottomRightRadius="4dp"
app:cornerTopRightRadius="4dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:strokeColor="@color/text_light_gray"
app:strokeWidth="1dp">
<TextView
android:id="@+id/textView42"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="+" />
</com.dreamgyf.android.ui.widget.shape.ShapeLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</com.dreamgyf.android.ui.widget.shape.ShapeLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
三、Java代码
使用RecyclerView通常需要三步:
- 编写Holder
- 编写Adaptor
- 为RecyclerView对象设置Adaptor和布局
为了使得体系更加清晰明了,我们把Holder作为Adaptor的内部类。
问题分析
在Adaptor onBindViewHolder()
方法中,需要给holder中注册过的部件设置值,每一个商店都有自己的值和嵌套的RecyclerView,每个内层RecyclerView中又都需要详细的信息,他们大概都是不同的。往常我们往往把数据设置为全局变量以方便访问,但内层数据有多个且输入不确定,内层布局中的数据该如何获取呢?
数据的解决方法
跟布局类似,我们需要把内层数据嵌套进外层数据中,并且在创建Adaptor时作为其私有属性传入,这样就把每个RecyclerView的数据绑定进其对应的Adaptor中。
为节省版面略去基础方法
内层数据实体类
public class ShopCarGoodItem {
private boolean selected;
private String imgUrl;
private String title;
private String ShippingForm;
private double price;
private int number;
}
外层数据实体类
public class ShopCarShopItem {
private boolean selected;
private String shopName;
private List<ShopCarGoodItem> shopCarGoods;
}
Adaptor的构造示例
先前我们提到过,把Holder作为Adaptor的内部类,还要为将数据绑定进去,再加上需要重写的三个方法,需要编写三块代码。
内层Adaptor代码
public class ShopCarGoodAdapter extends RecyclerView.Adapter<ShopCarGoodAdapter.ShopCarGoodViewHolder>{
private List<ShopCarGoodItem> shopCarGoodItems;
public ShopCarGoodAdapter(List<ShopCarGoodItem> shopCarGoodItems) {
this.shopCarGoodItems = shopCarGoodItems;
}
@NonNull
@Override
public ShopCarGoodViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view=LayoutInflater.from(getContext())
.inflate(R.layout.item_shopcar_goods,parent,false);
return new ShopCarGoodViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ShopCarGoodViewHolder holder, int position) {
holder.checkBox.setSelected(shopCarGoodItems.get(position).isSelected());
Glide.with(getContext())
.load(shopCarGoodItems.get(position).getImgUrl())
.into(holder.imageView);
holder.title.setText(shopCarGoodItems.get(position).getTitle());
holder.ShippingForm.setText("发货方式:"+shopCarGoodItems.get(position).getShippingForm());
holder.price.setText(String.format("¥ %.2f",shopCarGoodItems.get(position).getPrice()));
holder.number.setText(""+shopCarGoodItems.get(position).getNumber());
}
@Override
public int getItemCount() {
return shopCarGoodItems.size();
}
public class ShopCarGoodViewHolder extends RecyclerView.ViewHolder{
CheckBox checkBox;
ImageView imageView;
TextView title;
TextView ShippingForm;
TextView price;
TextView number;
public ShopCarGoodViewHolder(@NonNull View itemView) {
super(itemView);
checkBox=itemView.findViewById(R.id.ShopCarGoodCheckBox);
imageView=itemView.findViewById(R.id.ShopCarGoodImg);
title=itemView.findViewById(R.id.ShopCarGoodTitle);
ShippingForm=itemView.findViewById(R.id.ShopCarGoodShippingForm);
price=itemView.findViewById(R.id.ShopCarGoodPrice);
number=itemView.findViewById(R.id.ShopCarGoodNumbers);
}
}
}
外层Adaptor代码
public class ShopCarAdapter extends RecyclerView.Adapter<ShopCarAdapter.ShopCarViewHolder>{
private List<ShopCarShopItem> shopItems;
public ShopCarAdapter(List<ShopCarShopItem> shopItems) {
this.shopItems = shopItems;
}
@NonNull
@Override
public ShopCarViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view =LayoutInflater.from(getContext())
.inflate(R.layout.item_shopcar_shops,parent,false);
return new ShopCarViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ShopCarViewHolder holder, int position) {
holder.checkBox.setSelected(shopItems.get(position).isSelected());
holder.textView.setText(shopItems.get(position).getShopName());
ShopCarGoodAdapter shopCarGoodAdapter = new ShopCarGoodAdapter(shopItems.get(position).getShopCarGoods());
holder.recyclerView.setAdapter(shopCarGoodAdapter);
holder.recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
}
@Override
public int getItemCount() {
return shopItems.size();
}
public class ShopCarViewHolder extends RecyclerView.ViewHolder{
CheckBox checkBox;
TextView textView;
RecyclerView recyclerView;
public ShopCarViewHolder(@NonNull View itemView) {
super(itemView);
checkBox=itemView.findViewById(R.id.shopCheckBox);
textView=itemView.findViewById(R.id.shopname);
recyclerView=itemView.findViewById(R.id.shopGoodRecyclerView);
}
}
}
四、运行结果
应用外层RecyclerView
RecyclerView recyclerView = view.findViewById(R.id.shopsView);
ShopCarAdapter shopCarAdapter = new ShopCarAdapter(shopItems);
recyclerView.setAdapter(shopCarAdapter);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
评论区