一、前言:
上一篇:Android DataBinding的使用(三)列表展示
https://www.jianshu.com/p/acebb62eb477
gitHub 地址:https://github.com/lyyRunning/DataBindingDemo
今天主要是学习一下如何展示RecyclerView多类型列表,效果如下:(为了方便,不同的item采取不同的背景颜色)
二、思路:
其实在之前的博客中,曾经总结了这样一篇文章:
文中通过普通和面向接口实现的2种方式阐述了实现多类型列表的方式,核心思想还是:
1.创建不同的item_layout.xml文件
2.在代码中判断出不同的ViewType
3.创建出不同的ViewHolder
4.分开控制不同的item的响应事件(点击、触摸等)
但是通过上一篇文章,我们可以了解到DataBinding的一个优秀的特性——数据的双向绑定,因此我们可以通过创建一个万能的Adapter和ViewHolder实现若干个不同的列表,仅仅需要这样调用:
SimpleBindAdapter adapter = new SimpleBindAdapter(students, R.layout.item_recycler_view); //传入要展示的数据集合和item的布局文件
adapter.setItemPresenter(new RecyclerBindPresenter());//自定义响应事件
binding.recyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
binding.recyclerView.setAdapter(adapter);
很简单,只需要传入datas和子条目的布局文件就可以展示数据,如果要添加响应事件再加一行代码(当然这个Presenter需要自己实现),可以说是一劳永逸,原因就是因为我们已经把数据和控件之间的逻辑全部通过DataBinding进行了绑定,不再需要每一次都去自己实现Adapter。
既然可以一个Adapter+ViewHolder展示若干个列表,那么我们可以展示不同的item在同一个RecyclerView中吗?
当然可以,我们不难想象的到,我们需要解决的问题无非就是:
1.如何判断出不同的数据类型(ViewType)
2.不同type的item,布局文件如何展示
三、基本代码实现:
依赖:
//recyclerview的依赖
implementation 'com.android.support:recyclerview-v7:27.1.1'
//多种类型
compile 'me.drakeet.multitype:multitype:3.0.0'
不同的item布局文件编写:
1. item_recycler_view1.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="itemPresenter"
type="com.function.luo.activity.A04MulTypeRecyclerBindActivity.MulRecyclerBindPresenterI" />
<variable
name="data"
type="com.function.luo.bean.Student" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="80dp"
android:background="@color/colorAccent"
android:orientation="horizontal">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:gravity="center_vertical"
android:textAllCaps="false"
android:onClick="@{() -> itemPresenter.onNameClick(data)}"
android:text="@{`Student Name : `+ data.name.get()}" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:textAllCaps="false"
android:gravity="center_vertical"
android:onClick="@{() -> itemPresenter.onAgeClick(data)}"
android:text="@{`Student Age : `+data.age}" />
</LinearLayout>
</layout>
2. item_recycler_view2.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="itemPresenter"
type="com.function.luo.activity.A04MulTypeRecyclerBindActivity.MulRecyclerBindPresenterI" />
<variable
name="data"
type="com.function.luo.bean.Student" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="80dp"
android:background="@color/colorPrimary"
android:orientation="horizontal">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:textAllCaps="false"
android:gravity="center_vertical"
android:onClick="@{() -> itemPresenter.onNameClick(data)}"
android:text="@{`Student Name : `+ data.name.get()}" />
<!--显示年龄,点击年龄+3,同时paddingleft也绑定年龄-->
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAllCaps="false"
android:layout_margin="16dp"
android:gravity="center_vertical"
android:onClick="@{() -> itemPresenter.onAgeClick(data)}"
android:text="@{`Student Age : `+data.age}" />
</LinearLayout>
</layout>
3. 我们对数据类进行一个特殊的处理:
为了方便,我们的需求是,假设30岁以上的Student和30岁以下的Student展示不同类型的Item(背景色):
public class Student extends BaseObservable implements IMulTypeBindingBean {
public Student(String name, int age) {
this.name.set(name);
this.age = age;
}
private int age;
@Bindable
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
notifyPropertyChanged(BR.age);
}
public final ObservableField<String> name = new ObservableField<>();
/**
* IMulTypeBindingBean接口的实现方法
*
* 使用方法请见DataBinding多类型列表Activity的展示(该接口方法仅在该界面使用)
* {@link A04MulTypeRecyclerBindActivity}
*
* @return 如果30岁以下和30岁以上,数据展示在不同的layout上(背景色不同)
*/
@Override
public int getLayoutResouse() {
if (age <= 30) {
return R.layout.item_recycler_view1;
} else {
return R.layout.item_recycler_view2;
}
}
}
我们在这里,将item的布局文件作为ViewType的标识(R文件中的不同资源ID一定不同,所以正好作为ViewType在Adapter中进行判断)。
4.创建ViewHolder
因为DataBinding实现了Data和View的双向绑定,所以我们只需要这一个ViewHolder,无论是简单列表还是复杂的多类型列表,它一个就够了。
public class BaseViewHolder<T extends ViewDataBinding> extends RecyclerView.ViewHolder {
protected final T binding;
public BaseViewHolder(T t) {
super(t.getRoot());
this.binding = t;
}
public T getBinding() {
return binding;
}
}
5.Adapter代码如下:
我们接下来创建一劳永逸的Adapter:
public abstract class BaseBindingMulTypeAdapter<T extends IMulTypeBindingBean, D extends ViewDataBinding> extends RecyclerView.Adapter<BaseViewHolder<D>> {
private List<T> mDatas;
private int layoutId;
//用于设置Item的事件Presenter
protected IBaseBindingPresenter ItemPresenter;
public BaseBindingMulTypeAdapter(List<T> mDatas) {
this.mDatas = mDatas;
}
//我们直接获取数据集合中要展示的单个数据(Student),取得其layoutID作为ViewType返回
@Override
public int getItemViewType(int position) {
if (mDatas != null && !mDatas.isEmpty()) {
return mDatas.get(position).getLayoutResouse();
}
return super.getItemViewType(position);
}
//直接创建ViewHolder即可
@Override
public BaseViewHolder<D> onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
BaseViewHolder<D> viewHolder = new BaseViewHolder<D>((D) DataBindingUtil.inflate(inflater, viewType, parent, false));
onCreateViewHolder(viewHolder);
return viewHolder;
}
/**
* 如果有特殊需求可以实现在该方法中
* @param holder
*/
public abstract void onCreateViewHolder(BaseViewHolder<D> holder);
@Override
public void onBindViewHolder(BaseViewHolder<D> holder, int position) {
Log.i("tag", "onBindViewHolder");
holder.getBinding().setVariable(BR.data, mDatas.get(position));
holder.getBinding().setVariable(BR.itemPresenter, ItemPresenter);
holder.getBinding().executePendingBindings();
}
@Override
public int getItemCount() {
return mDatas == null ? 0 : mDatas.size();
}
/**
* 用于设置Item响应事件Presenter
*
* @param itemPresenter
* @return
*/
public BaseBindingMulTypeAdapter setItemPresenter(IBaseBindingPresenter itemPresenter) {
ItemPresenter = itemPresenter;
return this;
}
}
6.Activity中使用:
/**
* 多类型列表
*/
public class A04MulTypeRecyclerBindActivity extends AppCompatActivity {
private ActivityRecyclerBindBinding binding;
private RecyclerView recyclerView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
bind();
}
private void bind() {
binding = DataBindingUtil.setContentView(this, R.layout.activity_recycler_bind);
ArrayList<Student> students = getStudents();
MulTypeBindAdapter adapter = new MulTypeBindAdapter(students);
adapter.setItemPresenter(new MulRecyclerBindPresenterI());
binding.recyclerView
.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
binding.recyclerView
.setAdapter(adapter);
}
public class MulRecyclerBindPresenterI implements IBaseBindingPresenter {
public void onNameClick(Student student) {
Toast.makeText(A04MulTypeRecyclerBindActivity.this, student.name.get(), Toast.LENGTH_SHORT).show();
}
public void onAgeClick(Student student) {
Toast.makeText(A04MulTypeRecyclerBindActivity.this, String.valueOf(student.getAge()), Toast.LENGTH_SHORT).show();
}
}
private ArrayList<Student> getStudents() {
ArrayList<Student> students = new ArrayList<>();
students.add(new Student("jack", 36));
students.add(new Student("rose", 13));
students.add(new Student("qingmei2", 34));
students.add(new Student("unknown", 21));
return students;
}
}
因为我们已经将不同数据对应的item的layoutID放入了数据源students中,因此我们在Adapter的构造方法中只需要放入students即可。
到此,多类型列表展示,需求实现。
四、总结:
大概流程为:
- 创建不同类型item的xml布局文件
- 使对应的数据类(javaBean)实现IMulTypeBindingBean接口,在接口中返回该数据对应item类型的布局ID;
- 创建BaseViewHolder和BaseMulTypeAdapter,之后我们在实现列表时,再也不需要实现Adapter和ViewHolder,只需要复用即可
- Activity中初始化RecyclerView,设置Adapter和LayoutManager
原文链接:https://blog.csdn.net/mq2553299/article/details/72823153