RecyclerView 可以让您轻松高效地显示大量列表数据。您提供数据并定义每个列表项的外观,而 RecyclerView 库会根据需要动态创建元素。
当列表项滚动出屏幕时,RecyclerView不会销毁其视图,而是会被回收,对屏幕上滚动的新列表项重用该视图。RecyclerView可以让您轻松高效地显示大量数据。 可提升性能和应用的响应能力,并降低功耗。
一、简单使用
1. fragment_module.xml
在页面中添加一个RecyclerView布局,并将RecyclerView布局设置为线性布局、垂直分布、从上到下排列。
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_module"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="vertical"
app:layoutManager="LinearLayoutManager"
app:reverseLayout="false" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

2. item_module.xml
定义列表项的外观
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="data"
type="com.example.myapplication.bean.ModuleBean" />
</data>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="140dp">
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="8dp"
android:background="@drawable/shape_module_bg" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text='@{data.name, default="一个模块名"}' />
<TextView
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_gravity="top|end"
android:layout_marginEnd="8dp"
android:background="@drawable/shape_circle_tip"
android:gravity="center"
android:text='@{data.num+"", default=99}'
android:textColor="@color/white" />
</FrameLayout>
</layout>

3. ModuleRecyclerViewHolder.java
定义一个 ViewHolder ,用于存储列表项的一个布局实例。
我们可以在 ViewHolder 自由编写操作布局实例的函数,用于将数据渲染到布局上,例如 setStatus 函数。
public class ModuleRecyclerViewHolder extends RecyclerView.ViewHolder {
private final ItemModuleBinding binding;
public ModuleRecyclerViewHolder(@NonNull ItemModuleBinding binding) {
super(binding.getRoot());
this.binding = binding;
}
public ItemModuleBinding getBinding() {
return binding;
}
public void setStatus(int status) {
switch (status) {
case 0:
binding.tvStatus.setTextColor(ContextCompat.getColor(Utils.getContext(), R.color.primary));
binding.tvStatus.setBackgroundResource(R.color.primary_secondary);
binding.tvStatus.setText("待完成");
break;
case 1:
binding.tvStatus.setTextColor(ContextCompat.getColor(Utils.getContext(), R.color.error));
binding.tvStatus.setBackgroundResource(R.color.error_secondary);
binding.tvStatus.setText("未通过");
break;
case 2:
binding.tvStatus.setTextColor(ContextCompat.getColor(Utils.getContext(), R.color.info));
binding.tvStatus.setBackgroundResource(R.color.info_secondary);
binding.tvStatus.setText("已完成");
break;
}
}
}
4. ModuleRecyclerViewAdapter.java
定义一个 Adapter ,接收需要渲染的数据列表,重写 onCreateViewHolder 、 onBindViewHolder 、 getItemCount 。
public class ModuleRecyclerViewAdapter extends RecyclerView.Adapter<ModuleRecyclerViewHolder> {
List<ModuleBean> moduleBeans;
public ModuleRecyclerViewAdapter(List<ModuleBean> moduleBeans) {
this.moduleBeans = moduleBeans;
}
// 刷新数据
public void setModuleBeans(List<ModuleBean> newList) {
final List<TaskResponse> oldList = new ArrayList<>(tasklist);
DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new DiffUtil.Callback() {
@Override
public int getOldListSize() {
return oldList.size();
}
@Override
public int getNewListSize() {
return newList.size();
}
@Override
public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
return oldList.get(oldItemPosition).getId()
.equals(newList.get(newItemPosition).getId());
}
@Override
public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
return oldList.get(oldItemPosition).equals(newList.get(newItemPosition));
}
});
// 更新数据
moduleBeans.clear();
moduleBeans.addAll(newList);
// 只更新变化的部分,避免 notifyDataSetChanged()
diffResult.dispatchUpdatesTo(this);
}
// 增加数据,数据分页加载更多数据时使用
public void addModuleBeans(List<ModuleBean> newList) {
int positionStart = moduleBeans.size();
int itemCount = data.size();
moduleBeans.addAll(newList);
notifyItemRangeChanged(positionStart, itemCount);
}
@NonNull
@Override
public ModuleRecyclerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater from = LayoutInflater.from(parent.getContext());
ItemModuleBinding inflate = ItemModuleBinding.inflate(from, parent, false);
return new ModuleRecyclerViewHolder(inflate);
}
@Override
public void onBindViewHolder(@NonNull ModuleRecyclerViewHolder holder, int position) {
ModuleBean moduleBean = moduleBeans.get(position);
holder.getBinding().setData(moduleBean);
holder.setStatus(moduleBean.getStatus());
}
@Override
public int getItemCount() {
return moduleBeans.size();
}
}
5. DividerItemDecoration
通过 ItemDecoration 可以为 RecyclerView 的每一项添加间距和填充装饰。
在 getItemOffsets 函数中可以为每个子项设置上下左右的间距,类似于 padding 。如果 A 项的 bottom = 20,B 项的 top = 20,最终 A 和 B 之间的间隔就是 40(20+20)。
在 onDraw 函数中可以添加图片,绘制线条、矩形、圆形、扇形等图形,图形会显示在每个子项的下方,会在下一个子项绘制前绘制(如果没有下一项则不会绘制)。如果没有设置间隔,图形会与下一个子项重叠。
public class DividerItemDecoration extends RecyclerView.ItemDecoration {
private int space = 0;
private final Drawable divider;
public DividerItemDecoration(Context context) {
divider = ContextCompat.getDrawable(context, R.drawable.shape_divider); // 获取分隔线Drawable
assert divider != null;
space = divider.getIntrinsicHeight();
}
// 设置间隔
@Override
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
// 为每个子项设置上下左右的间距
if(parent.getChildAdapterPosition(view)==0){
outRect.set(0,0,0,0);
}else{
outRect.set(0,space,0,0);
}
}
// 填充装饰
@Override
public void onDraw(@NonNull Canvas c, RecyclerView parent, @NonNull RecyclerView.State state) {
int left = parent.getPaddingLeft();
int right = parent.getWidth() - parent.getPaddingRight();
for (int i = 0; i < parent.getChildCount() - 1; i++) {
View child = parent.getChildAt(i);
int top = child.getBottom();
int bottom = top + space;
divider.setBounds(left, top, right, bottom);
divider.draw(c);
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<size
android:width="20dp"
android:height="20dp" />
<solid android:color="@color/black"/>
</shape>
6. translate_module_item.xml 设置动画
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="500">
<translate
android:fromXDelta="100%"
android:toXDelta="0%" />
</set>
7. ModuleActivity.java
public class ModuleFragment extends BaseFragment<ModuleViewModel, FragmentModuleBinding> {
private ModuleRecyclerViewAdapter adapter;
// ViewModel
@Override
protected ModuleViewModel createViewModel() {
return new ViewModelProvider(this).get(ModuleViewModel.class);
}
// DataBinding
@Override
protected FragmentModuleBinding createDataBinding(LayoutInflater inflater, ViewGroup container) {
return FragmentModuleBinding.inflate(inflater, container, false);
}
@Override
protected void initView() {
adapter = new ModuleRecyclerViewAdapter(viewModel.modules.getValue());
binding.rvModule.setAdapter(adapter);
// 设置装饰
binding.rvModule.addItemDecoration(new DividerItemDecoration(getContext()));
// 设置平移动画
Animation animation = AnimationUtils.loadAnimation(getContext(), R.anim.translate_module_item);
binding.rvModule.setAnimation(animation);
}
@Override
protected void initData() {
viewModel.modules.observe(this, new Observer<List<ModuleBean>>() {
@Override
public void onChanged(List<ModuleBean> moduleBeans) {
adapter.setModuleBeans(moduleBeans);
}
});
}
}

二、基本介绍
RecyclerView 布局灵活,功能很多。
- 排列方式:线性列表、表格还有瀑布流布局
- 布局方向:垂直方向、水平方向
- 布局反转:垂直方向默认从上往下排列,反转后从下往上排列;水平方向默认从左往右排列,反转后从右往左排列
- 滚动条:设置滚动条和滚动槽
- 间隔装饰:设置子项之间的间隔距离和图片
- 动画:支持添加、删除、移动动画
1. 实现步骤
- 确定是线性布局还是网格布局
- 设计列表项中每个元素的外观和行为
- 扩展ViewHolder,定义列表项的所有功能
- 定义Adapter,将数据与ViewHolder绑定
2. 关键类
- RecyclerView:
RecyclerView是一个ViewGroup。因此,将RecyclerView添加到布局中的方式与添加任何其他界面元素相同。 - RecyclerView.Adapter:
Adapter会根据需要创建ViewHolder对象,将视图与其数据相关联。- onCreateViewHolder() 每当
RecyclerView需要创建新的ViewHolder时,它都会调用此方法。此方法会创建并初始化ViewHolder及其关联的View,但不会填充视图的内容,因为ViewHolder此时尚未绑定到具体数据。 - onBindViewHolder()
RecyclerView调用此方法将ViewHolder与数据相关联。此方法会提取适当的数据,并使用该数据填充 ViewHolder 的布局。例如,如果RecyclerView显示的是一个名称列表,该方法可能会在列表中查找适当的名称,并填充 ViewHolder 的TextViewwidget。 - getItemCount()
RecyclerView调用此方法来获取数据集的大小。例如,在通讯簿应用中,这可能是地址总数。RecyclerView 使用此方法来确定什么时候没有更多的列表项可以显示。
- onCreateViewHolder() 每当
- RecyclerView.ViewHolder:
ViewHolder是包含列表中各列表项的布局的View的封装容器。ViewHolder创建时,没有任何与之关联的数据。ViewHolder创建后,RecyclerView会将其“绑定”到其数据上。 - RecyclerView.LayoutManager: 布局管理器负责排列列表中的各个元素。你可以使用 RecyclerView 库提供的布局管理器之一,也可以自定义布局管理器。所有布局管理器都基于该库的
LayoutManager抽象类。- LinearLayoutManager: 线性布局
- GridLayoutManager: 网格布局
- StaggeredGridLayoutManager: 瀑布流布局
- 自定义布局管理器
- RecyclerView.ItemDecoration :
ItemDecoration允许应用程序从适配器的数据集向特定 item 视图添加特殊的绘图和布局偏移量。这对于在项目之间绘制分隔线、高亮显示、视觉分组边界等非常有用。
三、常用的属性和方法
1. 样式相关
在RecyclerView布局中用到的属性
<declare-styleable name="RecyclerView">
<!-- Class name of the Layout Manager to be used.
<p/>
The class must ext androidx.recyclerview.widget.RecyclerViewView$LayoutManager
and have either a default constructor or constructor with the signature
(android.content.Context, android.util.AttributeSet, int, int).
<p/>
If the name starts with a '.', application package is prefixed.
Else, if the name contains a '.', the classname is assumed to be a full class name.
Else, the recycler view package naandroidx.appcompat.widgetdget) is prefixed. -->
<attr format="string" name="layoutManager"/>
<!-- ============================= -->
<!-- Attributes for Layout Manager -->
<!-- ============================= -->
<eat-comment/>
<attr name="android:orientation"/>
<attr name="android:descendantFocusability"/>
<attr name="android:clipToPadding"/>
<attr format="integer" name="spanCount"/>
<attr format="boolean" name="reverseLayout"/>
<attr format="boolean" name="stackFromEnd"/>
<attr format="boolean" name="fastScrollEnabled"/>
<attr format="reference" name="fastScrollVerticalThumbDrawable"/>
<attr format="reference" name="fastScrollVerticalTrackDrawable"/>
<attr format="reference" name="fastScrollHorizontalThumbDrawable"/>
<attr format="reference" name="fastScrollHorizontalTrackDrawable"/>
</declare-styleable>
2. RecyclerView
- 布局管理器相关
setLayoutManager(LayoutManager manager):设置布局管理器,用于控制子视图的排列方式。常见的有LinearLayoutManager(线性布局)、GridLayoutManager(网格布局)和StaggeredGridLayoutManager(交错网格布局)。
- 数据适配器相关*
setAdapter(Adapter adapter):为 RecyclerView 设置适配器,负责提供数据并绑定到视图上。swapAdapter(Adapter adapter, boolean removeAndRecycleExistingViews):替换当前适配器,并决定是否移除并回收现有的视图。
- 视图缓存相关
setItemViewCacheSize(int size):设置 RecyclerView 应该缓存的额外视图数量,这些视图缓存可以在用户滚动时快速重用。setRecycledViewPool(RecyclerView.RecycledViewPool pool):设置共享的视图池,这对于嵌套的 RecyclerView 特别有用。getRecycledViewPool():获取当前使用的视图池。setHasFixedSize(boolean hasFixedSize):如果可以确定 RecyclerView 的大小不会因为内容的变化而变化,则可以设置此属性为true来优化性能。
- 滚动与动画相关
scrollToPosition(int position):滚动到指定位置。smoothScrollToPosition(int position):平滑滚动到指定位置。setItemAnimator(ItemAnimator animator):设置项目添加、删除等操作的动画效果,默认使用DefaultItemAnimator。setItemAnimator(null):禁用默认动画。
- 分割线与装饰
addItemDecoration(ItemDecoration decor):添加分割线或其他装饰。removeItemDecoration(ItemDecoration decor):移除之前添加的装饰。
- 其他常用方法
addOnScrollListener(OnScrollListener listener):添加滚动监听器,用于检测滚动事件。addOnItemTouchListener(OnItemTouchListener listener):添加触摸事件监听器,可用于实现点击或长按等功能。findViewHolderForAdapterPosition(int position):根据适配器中的位置找到对应的 ViewHolder。getAdapter():获取当前设置的 Adapter。setLayoutFrozen(boolean freeze):冻结布局更新,适用于需要暂停 UI 更新的情况。setNestedScrollingEnabled(boolean enabled):启用或禁用嵌套滚动。setOverScrollMode(int mode):它属于View类的一个方法,设置视图到达边界时的过度模式(none, ifContentScrolls, always)。setClipToPadding(boolean clipToPadding):是否裁剪到填充边界,默认是true。
3. RecyclerView.Adapter
- 可以重写的函数
onCreateViewHolder(ViewGroup parent, int viewType):这是适配器中必须实现的方法之一,当需要一个新的 ViewHolder 来展示某个类型的条目时会调用此方法。在这里你应该创建并返回一个新的 ViewHolder 实例。onBindViewHolder(ViewHolder holder, int position):这也是一个必需实现的方法,用于将数据绑定到特定位置的 ViewHolder 上。当你需要显示或更新某个条目的时候,这个方法会被调用。getItemCount():返回数据集中条目的总数。RecyclerView 使用这个值来确定有多少个条目需要被展示。getItemViewType(int position):根据条目的位置获取其类型。这对于支持多种不同类型的条目布局非常有用。onViewRecycled(ViewHolder holder):当一个 ViewHolder 被回收且不再使用时调用。可以用来释放资源或者取消网络请求等操作。onViewAttachedToWindow(ViewHolder holder)和onViewDetachedFromWindow(ViewHolder holder):这两个方法分别在 ViewHolder 被附加到窗口(即将显示)和从窗口分离(即将隐藏)时调用。onAttachedToRecyclerView(RecyclerView recyclerView):当 Adapter 被附加到 RecyclerView 时调用。可以在此初始化与 RecyclerView 相关的操作。onDetachedFromRecyclerView(RecyclerView recyclerView):当 Adapter 从 RecyclerView 分离时调用。通常用于清理资源。
- 数据操作相关方法
getItemCount():返回数据集中的条目总数。RecyclerView 使用这个方法来确定有多少个条目需要展示。notifyDataSetChanged():通知适配器数据集发生了变化,这会导致整个列表重新绘制。notifyItemChanged(int position):通知适配器特定位置的数据已经改变,导致该位置的视图更新。notifyItemInserted(int position):通知适配器在特定位置插入了一个新条目。notifyItemRemoved(int position):通知适配器从特定位置移除了一个条目。notifyItemRangeChanged(int positionStart, int itemCount):通知适配器从positionStart开始的itemCount个条目已更改。notifyItemRangeInserted(int positionStart, int itemCount):通知适配器从positionStart开始插入了itemCount个条目。notifyItemRangeRemoved(int positionStart, int itemCount):通知适配器从positionStart开始移除了itemCount个条目。
- 视图类型管理
getItemViewType(int position):返回给定位置条目的视图类型。如果您的列表中有多种类型的条目,您可以通过重写此方法来区分它们。
- 其他方法
setHasStableIds(boolean hasStableIds):设置是否应该使用稳定的 ID。稳定 ID 可以提高性能,特别是在动画方面。getItemId(int position):返回指定位置条目的 ID。只有在设置了稳定 ID 后才需要实现此方法。
4. RecyclerView.ViewHolder
- 公共函数
getAdapterPosition():返回该 ViewHolder 在 Adapter 数据集中的位置。如果该 ViewHolder 当前未绑定到任何数据项,则返回RecyclerView.NO_POSITION。getAbsoluteAdapterPosition():返回 ViewHolder 在整个 Adapter 中的绝对位置(包括 Header、Footer 等)。如果无法确定绝对位置,则返回RecyclerView.NO_POSITION。getLayoutPosition():返回该 ViewHolder 在布局中的位置。如果发生了动画或布局变动,可能与getAdapterPosition()返回的值不同。getOldPosition():返回在最近一次布局之前 ViewHolder 所在的位置。这在处理动画时可能会有用。isRecyclable()和setIsRecyclable(boolean recyclable):判断 ViewHolder 是否可被回收,并允许设置是否可以回收。当需要暂时阻止 ViewHolder 被回收时,可以使用此方法。isInvalid():检查 ViewHolder 是否已经无效,即它不再对应于任何数据项。isBound():检查 ViewHolder 是否已经绑定了数据。注意,这是一个包私有的方法,通常不会直接使用。
- 公共属性
itemView:这是 ViewHolder 的一个公开字段,代表当前条目的根视图。通过这个字段可以直接访问条目的顶层视图。
- 其他函数
findViewHolderForAdapterPosition(int position)和findViewHolderForLayoutPosition(int position):这两个方法是 RecyclerView 提供的静态方法,用于根据 Adapter 或 Layout 位置获取相应的 ViewHolder 实例 。
5. RecyclerView.ItemDecoration
- 可以重写的函数
getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state):该方法用于设置每个项的外边距(如分隔线的间距)。outRect 传递的是矩形,用来定义左、上、右、下的间距。onDraw(Canvas c, RecyclerView parent, RecyclerView.State state):用于绘制每个子项的装饰,比如分隔线或自定义的图形。onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state):在所有子项绘制之后调用,可以用来绘制覆盖在子项之上的装饰。
- 其他方法
setDrawable(Drawable drawable):如果装饰需要使用Drawable来绘制某种图形或分隔线,可以通过该方法来设置。setSpacing(int space):有时我们会为子项设置固定的间距,可以使用此方法来调整ItemDecoration的间距。setPadding(int left, int top, int right, int bottom):用于设置每个项的内边距。
未完待续……
3130



被折叠的 条评论
为什么被折叠?



