概念
什么是recyclerView?我们常见的可以滑动的,分块的视图样式就可以认为是recyclerView。
比如:
在开发前还需要了解一些概念:
ViewHolder:可以看到recyclerView是以分块的视图形式组织的。分块无论其形状,里面的内容如何,每一个分快称之为ViewHolder。上图中一个title+subtitle的条形分块就是一个ViewHolder。
Adapter:可以确认的是,recyclerView一定是有数据填充的,也一定有一个工具性质的东西能够将数据正确地和每一个ViewHolder绑定,进而渲染其内容。实现这个流程的工具就是Adapter。
知道以上概念之后就可以开发了。
1.创建recylerView视图与对象
首先在需要展示的view里创建一个recyclerView:
<?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"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
随后在代码中获取其对象:
mRecyclerView = this.findViewById(R.id.recycler_view);
此外,viewHolder的视图也需要自定义
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/list_item">
<TextView
android:id="@+id/main_title"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:textSize="30sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_centerVertical="true"
tools:text="你好"/>
<TextView
android:id="@+id/subtitle"
app:layout_constraintLeft_toLeftOf="@id/main_title"
app:layout_constraintTop_toBottomOf="@id/main_title"
android:layout_marginTop="10dp"
android:textSize="12sp"
android:layout_height="20dp"
android:layout_width="wrap_content"
android:layout_centerVertical="true"
tools:text="是的"/>
</androidx.constraintlayout.widget.ConstraintLayout>
2.创建数据类型
为了方便组织代码,我们通常将每个viewHolder中需要用到的数据抽象成一个data object。
public class ItemDTO {
public String Title;
public String subTitle;
}
这里为了方便,本地mock出一组给recylerView使用的数据(数组)。
private void mockData() {
itemDTOList = new ArrayList<>();
for (int i = 0; i < 20 ;i++) {
ItemDTO itemDTO = new ItemDTO();
itemDTO.Title = "title" + i;
itemDTO.subTitle = "subtitle" + i;
itemDTOList.add(itemDTO);
}
}
3.创建adapter和viewHolder
这是最难的一步,先贴上代码。
package recyclerview;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import com.example.myapplication.R;
import java.util.List;
public class ListViewAdapter extends RecyclerView.Adapter<ListViewAdapter.viewHolder> {
private final static String TAG = "ListViewAdapter";
// 绑定在recyclerView的数据集
private final List<ItemDTO> mItemDTOList;
public ListViewAdapter(List<ItemDTO> mItemDTOList) {
this.mItemDTOList = mItemDTOList;
}
/**
* 首次创建viewHolder时调用
* @param parent
* @param viewType
* @return
*/
@Override
public viewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Log.d(TAG, "onCreateViewHolder");
// 创建viewHolder
View viewHolder = View.inflate(parent.getContext(), R.layout.list_view_item, null);
return new ListViewAdapter.viewHolder(viewHolder);
}
/**
* 上下滑动recyclerView调用
* @param holder
* @param position
*/
@Override
public void onBindViewHolder(ListViewAdapter.viewHolder holder, int position) {
// 给对应位置的viewHolder绑定数据
holder.bindData(mItemDTOList.get(position));
}
@Override
public int getItemCount() {
if (mItemDTOList == null || mItemDTOList.isEmpty()) {
return 0;
} else {
return mItemDTOList.size();
}
}
/**
* viewHolder对象
*/
public class viewHolder extends RecyclerView.ViewHolder {
private final TextView mMainTitle;
private final TextView mSubtitle;
public viewHolder(View itemView) {
super(itemView);
mMainTitle = itemView.findViewById(R.id.main_title);
mSubtitle = itemView.findViewById(R.id.subtitle);
}
/**
* 将数据映射到每个viewHolder的视图上
* @param itemDTO
*/
public void bindData(ItemDTO itemDTO) {
mMainTitle.setText(itemDTO.Title);
mSubtitle.setText(itemDTO.subTitle);
Log.d(TAG, "bindData: title = " + itemDTO.Title + " , subtitle = " + itemDTO.subTitle);
}
}
}
viewHolder
自定义的viewHolder集成了安卓原生的viewHolder,并自己实现了一个核心方法。
viewHolder有两个任务:
1.初始化viewHolder的视图组件
2.提供数据绑定的方法,将之前定义的data object里的数据设置到视图中。
核心方法:bindData,将data object里的数据设置到视图组件中。
Adapter
自定义的adapter继承了安卓原生的adapter,并重写两个核心方法。
adapter有三个任务:
1.获取到需要绑定到整个recyclerView的数据集。
2.在创建viewHolder时,创建自定义的viewHolder。
3.在绑定数据时,将对应的data object传给对应的viewHolder。
核心方法onCreateViewHolder:
调用时机:每个viewHolder被创建时(不一定每个都创建)
recyclerView有复用viewHolder的机制,即同一个类型的viewHolder不会一直重复创建。尤其是整个recylerView只有一种viewHolder时,在第一次填满整个屏幕后通常就不会再创建viewHolder了,而是通过重复绑定数据来刷新视图,给用户一种不断滑动的感觉。
因此在创建viewHolder时,我们只需要把viewHolder inflate出来,并返回即可。
核心方法onBindViewHolder:
调用时机:每个viewHolder被绑定数据时(每个都被绑数据)
从刚才的描述可以得知,数据绑定这一操作是贯彻在滑动过程中的。该方法调用时会传入当前的viewHolder和当前viewHolder在整个recyclerView的位置。
因此在绑定数据时,我们只需要执行每个viewHolder的bindData即可。
4.设置recylerView
private void initData() {
// 填充数据
mockData();
// 创建adapter 必须
ListViewAdapter listViewAdapter = new ListViewAdapter(itemDTOList);
// 设置recyclerView的排列模式 必须
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(linearLayoutManager);
// 设置adapter 必须
mRecyclerView.setAdapter(listViewAdapter);
}
recylerView必须设置的两个元素:排列模式和adapter,否则无法正确运行。