onPageScrolled 是一个在 Android 开发中非常常见的回调方法,主要用于 ViewPager(以及其继承者 ViewPager2)和 RecyclerView,当用户滚动页面或列表时,系统会不断调用这个方法,让你能够实时跟踪滚动的状态并进行相应处理。

(图片来源网络,侵删)
虽然它主要用于这两个组件,但其核心参数的含义是相通的,下面我们以最常见的 ViewPager 和 RecyclerView 为例来解释。
核心参数详解
onPageScrolled 方法通常接收三个核心参数,它们的顺序和含义在 ViewPager 和 RecyclerView 中略有不同,但本质上是相似的。
对于 ViewPager / ViewPager2
在 ViewPager.OnPageChangeListener 或 ViewPager2.OnPageChangeCallback 中,onPageScrolled 的定义如下:
// 适用于 ViewPager 和 ViewPager2 void onPageScrolled(int position, float positionOffset, int positionOffsetPixels);
参数详解:

(图片来源网络,侵删)
| 参数 | 类型 | 含义 |
|---|---|---|
position |
int |
当前可见的第一个页面的索引,这是最重要的参数,当用户滚动时,这个值在页面完全切换前是不会改变的,如果你在滑动第 0 页和第 1 页之间,position 始终是 0,当滑动超过一半,页面“跳”到第 1 页时,position 才会变为 1。 |
positionOffset |
float |
当前页面偏移的百分比,这是一个 0.0 到 1.0 之间的浮点数。 • 0 表示当前页面完全显示。 • 0 表示当前页面已经完全被下一个页面覆盖( position 即将改变)。这个值非常适合用来制作平滑的动画效果,你可以用它来让标题栏的透明度或颜色随滑动而渐变。 |
positionOffsetPixels |
int |
当前页面偏移的像素值,这是 positionOffset 乘以页面宽度后的实际像素数,它提供了更精确的滚动位置,适合用于需要基于像素进行计算的动画或布局调整。 |
示例: 假设你正在从第 0 页滑动到第 1 页:
- 滑动开始时:
position=0,positionOffset=0.0,positionOffsetPixels=0 - 滑动到一半时:
position=0,positionOffset=0.5,positionOffsetPixels=屏幕宽度的一半 - 滑动即将结束时:
position=0,positionOffset≈0.99,positionOffsetPixels≈屏幕宽度 - 滑动完成,页面切换到第 1 页:
position=1,positionOffset=0.0,positionOffsetPixels=0
对于 RecyclerView
在 RecyclerView.OnScrollListener 中,onScrolled 方法被用来监听滚动事件,它的功能与 ViewPager 的 onPageScrolled 类似,但参数更多,因为它处理的是列表而非单个页面。
// 适用于 RecyclerView void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy);
参数详解:
| 参数 | 类型 | 含义 |
|---|---|---|
recyclerView |
RecyclerView |
触发滚动事件的 RecyclerView 实例本身,如果你有多个 RecyclerView,可以通过这个参数来区分是哪一个在滚动。 |
dx |
int |
水平滚动的像素距离,表示自上次回调以来,内容在 X 轴方向上滚动的距离。 • 正值向左滚动(手指向左滑动)。 • 负值向右滚动(手指向右滑动)。 • 0:没有水平滚动。 |
dy |
int |
垂直滚动的像素距离,表示自上次回调以来,内容在 Y 轴方向上滚动的距离。 • 正值向上滚动(手指向上滑动)。 • 负值向下滚动(手指向下滑动)。 • 0:没有垂直滚动。 |
示例:

(图片来源网络,侵删)
- 用户向上滑动屏幕(向下滚动列表):
dy为一个正数(+50)。
- 用户向下滑动屏幕(向上滚动列表):
dy为一个负数(-30)。
- 用户左右滑动列表:
dx会相应地变为正数或负数,而dy为0。
如何使用这些参数?(常见场景)
ViewPager 实现标题栏联动
这是一个非常经典的需求:当用户滑动页面时,标题栏的文字或指示器会随之变化。
// 假设你有一个标题栏和 ViewPager
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
// 在这里实现平滑过渡效果
// 改变标题颜色
if (positionOffset > 0 && position < titles.length - 1) {
// 当前 position 和下一页 positionOffset 混合颜色
float ratio = positionOffset;
int currentColor = blendColor(Color.RED, Color.BLUE, ratio);
tvTitle.setTextColor(currentColor);
}
}
@Override
public void onPageSelected(int position) {
// 页面完全选中时,设置最终标题
tvTitle.setText(titles[position]);
}
@Override
public void onPageScrollStateChanged(int state) {
// 滚动状态改变
}
});
RecyclerView 实现悬浮吸顶效果
当 RecyclerView 滚动时,你可能想让某个子 View(如分类标题)固定在顶部。
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
private int lastDy = 0;
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
// dy > 0 表示向下滑动,dy < 0 表示向上滑动
if (dy > 0) {
// 向下滑动,隐藏悬浮按钮或标题
if (lastDy >= 0) { // 确保是持续向下滑动
hideFloatingButton();
}
} else {
// 向上滑动,显示悬浮按钮或标题
if (lastDy <= 0) { // 确保是持续向上滑动
showFloatingButton();
}
}
lastDy = dy;
}
});
总结与对比
| 特性 | ViewPager.onPageScrolled |
RecyclerView.onScrolled |
|---|---|---|
| 主要用途 | 监听页面之间的切换滚动 | 监听列表在任意方向的滚动 |
| 核心参数 | position, positionOffset, positionOffsetPixels |
dx, dy (像素距离) |
| 关注点 | 页面状态(当前是哪一页,切换进度) | 滚动方向和距离(像素级控制) |
| 典型应用 | 页面切换动画、标题栏联动、Tab指示器 | 悬浮吸顶、加载更多、显示/隐藏控件、下拉刷新 |
ViewPager的onPageScrolled告诉你“我在从第 A 页滑到第 B 页,现在滑了百分之 X”。RecyclerView的onScrolled告诉你“列表在 Y 轴上滚动了 Z 个像素”。
理解这些参数的含义是掌握 Android 中滚动交互和实现复杂动画效果的关键。
