Google I/O 2019 更新
ViewPager2 来了!
Google just announced 在“What's New in Android”(又名“Android 主题演讲”)演讲中表示,他们正在开发基于 RecyclerView 的新 ViewPager!
来自幻灯片:
类似于 ViewPager,但更好
- 从 ViewPager 轻松迁移
- 基于 RecyclerView
- 支持从右到左的模式
- 允许垂直分页
- 改进的数据集更改通知
您可以查看最新版本here 和发行说明here。还有一个official sample。 2021 年 12 月更新:示例已移至 this other repo。
个人意见:我认为这是一个非常需要的补充。我最近在PagerSnapHelper oscillating left right indefinitely 遇到了很多麻烦 - 请参阅the ticket 我已经打开了。
新答案(2016 年)
您现在可以只使用SnapHelper。
如果您想要类似于ViewPager 的中心对齐捕捉行为,请使用PagerSnapHelper:
SnapHelper snapHelper = new PagerSnapHelper();
snapHelper.attachToRecyclerView(recyclerView);
还有一个LinearSnapHelper。我试过了,如果你用能量一扔,那么它会用 1 次扔滚动 2 个项目。我个人不喜欢它,但请自行决定 - 尝试只需几秒钟。
原始答案(2016 年)
经过许多小时的尝试,在 SO 中找到了 3 种不同的解决方案,我终于构建了一个非常接近 ViewPager 中的行为的解决方案。
该解决方案基于@eDizzle solution,我相信我已经对其进行了足够的改进,可以说它几乎可以像ViewPager 一样工作。
重要提示:我的RecyclerView 项目宽度与屏幕完全相同。我没有尝试过其他尺寸。我也将它与水平 LinearLayoutManager 一起使用。如果你想要垂直滚动,我认为你需要调整代码。
这里有代码:
public class SnappyRecyclerView extends RecyclerView {
// Use it with a horizontal LinearLayoutManager
// Based on https://*.com/a/29171652/4034572
public SnappyRecyclerView(Context context) {
super(context);
}
public SnappyRecyclerView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public SnappyRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
public boolean fling(int velocityX, int velocityY) {
LinearLayoutManager linearLayoutManager = (LinearLayoutManager) getLayoutManager();
int screenWidth = Resources.getSystem().getDisplayMetrics().widthPixels;
// views on the screen
int lastVisibleItemPosition = linearLayoutManager.findLastVisibleItemPosition();
View lastView = linearLayoutManager.findViewByPosition(lastVisibleItemPosition);
int firstVisibleItemPosition = linearLayoutManager.findFirstVisibleItemPosition();
View firstView = linearLayoutManager.findViewByPosition(firstVisibleItemPosition);
// distance we need to scroll
int leftMargin = (screenWidth - lastView.getWidth()) / 2;
int rightMargin = (screenWidth - firstView.getWidth()) / 2 + firstView.getWidth();
int leftEdge = lastView.getLeft();
int rightEdge = firstView.getRight();
int scrollDistanceLeft = leftEdge - leftMargin;
int scrollDistanceRight = rightMargin - rightEdge;
if (Math.abs(velocityX) < 1000) {
// The fling is slow -> stay at the current page if we are less than half through,
// or go to the next page if more than half through
if (leftEdge > screenWidth / 2) {
// go to next page
smoothScrollBy(-scrollDistanceRight, 0);
} else if (rightEdge < screenWidth / 2) {
// go to next page
smoothScrollBy(scrollDistanceLeft, 0);
} else {
// stay at current page
if (velocityX > 0) {
smoothScrollBy(-scrollDistanceRight, 0);
} else {
smoothScrollBy(scrollDistanceLeft, 0);
}
}
return true;
} else {
// The fling is fast -> go to next page
if (velocityX > 0) {
smoothScrollBy(scrollDistanceLeft, 0);
} else {
smoothScrollBy(-scrollDistanceRight, 0);
}
return true;
}
}
@Override
public void onScrollStateChanged(int state) {
super.onScrollStateChanged(state);
// If you tap on the phone while the RecyclerView is scrolling it will stop in the middle.
// This code fixes this. This code is not strictly necessary but it improves the behaviour.
if (state == SCROLL_STATE_IDLE) {
LinearLayoutManager linearLayoutManager = (LinearLayoutManager) getLayoutManager();
int screenWidth = Resources.getSystem().getDisplayMetrics().widthPixels;
// views on the screen
int lastVisibleItemPosition = linearLayoutManager.findLastVisibleItemPosition();
View lastView = linearLayoutManager.findViewByPosition(lastVisibleItemPosition);
int firstVisibleItemPosition = linearLayoutManager.findFirstVisibleItemPosition();
View firstView = linearLayoutManager.findViewByPosition(firstVisibleItemPosition);
// distance we need to scroll
int leftMargin = (screenWidth - lastView.getWidth()) / 2;
int rightMargin = (screenWidth - firstView.getWidth()) / 2 + firstView.getWidth();
int leftEdge = lastView.getLeft();
int rightEdge = firstView.getRight();
int scrollDistanceLeft = leftEdge - leftMargin;
int scrollDistanceRight = rightMargin - rightEdge;
if (leftEdge > screenWidth / 2) {
smoothScrollBy(-scrollDistanceRight, 0);
} else if (rightEdge < screenWidth / 2) {
smoothScrollBy(scrollDistanceLeft, 0);
}
}
}
}
享受吧!