RecyclerView/SnapHelper - 如何设置卡片的可变位置,以便它们根据位置以不同方式查看
RecyclerView/SnapHelper - How to set variable position of the cards so that they peek differently based on position
我是 android 的新手,因此 RV 和我正在尝试实现第一张和最后一张卡片不居中的布局,而是在它们之后和之前显示更多卡片。也许在这种情况下,我可以看到第二张卡片的 16dp 和倒数第二张卡片的相同情况,这使得第一张和最后一张卡片不居中。
但其余卡片每张 8dp,因此中间卡片居中显示。也许以某种方式为第二张和倒数第二张卡片使用 itemDecoration。
我能够按照此处的建议显示下一张和上一张卡片的部分内容,但这只会使所有卡片统一居中:
我尝试覆盖 getItemOffsets 但每次滚动到第一张或最后一张卡片时都会触发它,并且错误地将第二张和第二张卡片移动到最后一张卡片
而且当我滚动到它们时也没有正确地将它们居中。
public static class MyItemDecoration extends RecyclerView.ItemDecoration {
@Override
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
final int itemPosition = parent.getChildAdapterPosition(view);
if (itemPosition == RecyclerView.NO_POSITION) {
return;
}
final int itemCount = state.getItemCount();
if (itemCount > 0 && itemPosition == 1) {
outRect.left -= 16;
outRect.right -= 16;
}
else if (itemCount > 0 && itemPosition == itemCount - 1) {
outRect.left += 16;
outRect.right += 16;
}
}
}
房车设置
SnapHelper snapHelper = new PagerSnapHelper();
RecyclerView rv = getBinding().rv;
rv.setOnFlingListener(null);
snapHelper.attachToRecyclerView(rv);
PagerSnapHelper 将 RecyclerView 项目(包括装饰)居中,因此,除非装饰宽度平衡,否则它们不会始终居中.这可能就是您所看到的。
尝试以下装饰。此代码将 full-width 修饰应用于第一项的开头和最后一项的结尾;否则,使用一半装饰宽度。通过以这种方式设置装饰,您可以使左右装饰平衡的项目居中。
DividerItemDecoration decoration =
new DividerItemDecoration(getApplicationContext(), HORIZONTAL) {
private int mDecorationWidth = (int) (getResources().getDisplayMetrics().density * 8);
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
RecyclerView.State state) {
final int pos = parent.getChildAdapterPosition(view);
if (pos == RecyclerView.NO_POSITION) {
return;
}
if (pos == 0) {
outRect.set(mDecorationWidth, 0, mDecorationWidth / 2, 0);
} else if (pos == parent.getAdapter().getItemCount() - 1) {
outRect.set(mDecorationWidth / 2, 0, mDecorationWidth, 0);
} else {
outRect.set(mDecorationWidth / 2, 0, mDecorationWidth / 2, 0);
}
}
};
这是一个显示带有灰色垂直分隔线的结果的视频。
如果装饰效果已经令您满意,您可以覆盖 PagerSnapHelper 中的 calculateDistanceToFinalSnap()
以使除第一个和最后一个视图之外的所有视图居中,如下所示。参见 calculatedistancetofinalsnap()。一旦 PageSnapHelper 识别出要捕捉到的目标视图,就会调用 calculatedistancetofinalsnap()
来确定要移动多少像素以执行捕捉。在这里,我们移动的像素刚好足以使 RecyclerView 中的视图居中(没有装饰)。 PageSnapHelper 为第一个和最后一个项目做正确的事情,所以我们只为这些调用 super。
PagerSnapHelper pagerSnapHelper = new PagerSnapHelper() {
@Override
public int[] calculateDistanceToFinalSnap(@NonNull RecyclerView.LayoutManager layoutManager,
@NonNull View targetView) {
LinearLayoutManager lm = (LinearLayoutManager) layoutManager;
int pos = mRecycler.getChildAdapterPosition(targetView);
// If first or last view, the default implementation works.
if (pos == 0 || pos == lm.getItemCount() - 1) {
return super.calculateDistanceToFinalSnap(layoutManager, targetView);
}
// Force centering in the view without its decorations.
// targetCenter is the location of the center of the view we want to center.
int targetCenter = targetView.getLeft() + targetView.getWidth() / 2;
// Distance is the number of pixels to move the target so that its center
// lines up with the center of the RecyclerView (mRecycler.getWidth() / 2)
int distance = targetCenter - mRecycler.getWidth() / 2;
return new int[]{distance, 0};
}
};
两种方法都行。
我是 android 的新手,因此 RV 和我正在尝试实现第一张和最后一张卡片不居中的布局,而是在它们之后和之前显示更多卡片。也许在这种情况下,我可以看到第二张卡片的 16dp 和倒数第二张卡片的相同情况,这使得第一张和最后一张卡片不居中。 但其余卡片每张 8dp,因此中间卡片居中显示。也许以某种方式为第二张和倒数第二张卡片使用 itemDecoration。
我能够按照此处的建议显示下一张和上一张卡片的部分内容,但这只会使所有卡片统一居中:
我尝试覆盖 getItemOffsets 但每次滚动到第一张或最后一张卡片时都会触发它,并且错误地将第二张和第二张卡片移动到最后一张卡片 而且当我滚动到它们时也没有正确地将它们居中。
public static class MyItemDecoration extends RecyclerView.ItemDecoration {
@Override
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
final int itemPosition = parent.getChildAdapterPosition(view);
if (itemPosition == RecyclerView.NO_POSITION) {
return;
}
final int itemCount = state.getItemCount();
if (itemCount > 0 && itemPosition == 1) {
outRect.left -= 16;
outRect.right -= 16;
}
else if (itemCount > 0 && itemPosition == itemCount - 1) {
outRect.left += 16;
outRect.right += 16;
}
}
}
房车设置
SnapHelper snapHelper = new PagerSnapHelper();
RecyclerView rv = getBinding().rv;
rv.setOnFlingListener(null);
snapHelper.attachToRecyclerView(rv);
PagerSnapHelper 将 RecyclerView 项目(包括装饰)居中,因此,除非装饰宽度平衡,否则它们不会始终居中.这可能就是您所看到的。
尝试以下装饰。此代码将 full-width 修饰应用于第一项的开头和最后一项的结尾;否则,使用一半装饰宽度。通过以这种方式设置装饰,您可以使左右装饰平衡的项目居中。
DividerItemDecoration decoration =
new DividerItemDecoration(getApplicationContext(), HORIZONTAL) {
private int mDecorationWidth = (int) (getResources().getDisplayMetrics().density * 8);
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
RecyclerView.State state) {
final int pos = parent.getChildAdapterPosition(view);
if (pos == RecyclerView.NO_POSITION) {
return;
}
if (pos == 0) {
outRect.set(mDecorationWidth, 0, mDecorationWidth / 2, 0);
} else if (pos == parent.getAdapter().getItemCount() - 1) {
outRect.set(mDecorationWidth / 2, 0, mDecorationWidth, 0);
} else {
outRect.set(mDecorationWidth / 2, 0, mDecorationWidth / 2, 0);
}
}
};
这是一个显示带有灰色垂直分隔线的结果的视频。
如果装饰效果已经令您满意,您可以覆盖 PagerSnapHelper 中的 calculateDistanceToFinalSnap()
以使除第一个和最后一个视图之外的所有视图居中,如下所示。参见 calculatedistancetofinalsnap()。一旦 PageSnapHelper 识别出要捕捉到的目标视图,就会调用 calculatedistancetofinalsnap()
来确定要移动多少像素以执行捕捉。在这里,我们移动的像素刚好足以使 RecyclerView 中的视图居中(没有装饰)。 PageSnapHelper 为第一个和最后一个项目做正确的事情,所以我们只为这些调用 super。
PagerSnapHelper pagerSnapHelper = new PagerSnapHelper() {
@Override
public int[] calculateDistanceToFinalSnap(@NonNull RecyclerView.LayoutManager layoutManager,
@NonNull View targetView) {
LinearLayoutManager lm = (LinearLayoutManager) layoutManager;
int pos = mRecycler.getChildAdapterPosition(targetView);
// If first or last view, the default implementation works.
if (pos == 0 || pos == lm.getItemCount() - 1) {
return super.calculateDistanceToFinalSnap(layoutManager, targetView);
}
// Force centering in the view without its decorations.
// targetCenter is the location of the center of the view we want to center.
int targetCenter = targetView.getLeft() + targetView.getWidth() / 2;
// Distance is the number of pixels to move the target so that its center
// lines up with the center of the RecyclerView (mRecycler.getWidth() / 2)
int distance = targetCenter - mRecycler.getWidth() / 2;
return new int[]{distance, 0};
}
};
两种方法都行。