我想使用 aRecyclerView
来模拟 a 的行为MultiViewPager
,特别是我希望将所选项目放在屏幕的中心,包括第一个和最后一个元素。
我所做的是设置一个RecyclerView
水平LinearLayoutManager
和一个LinearSnapHelper
。这个解决方案的问题是第一个和最后一个项目永远不会水平居中作为选择。我应该切换我的代码以使其使用 aMultiViewPager
还是可以利用 a 来实现类似的结果RecyclerView
?
我想使用 aRecyclerView
来模拟 a 的行为MultiViewPager
,特别是我希望将所选项目放在屏幕的中心,包括第一个和最后一个元素。
我所做的是设置一个RecyclerView
水平LinearLayoutManager
和一个LinearSnapHelper
。这个解决方案的问题是第一个和最后一个项目永远不会水平居中作为选择。我应该切换我的代码以使其使用 aMultiViewPager
还是可以利用 a 来实现类似的结果RecyclerView
?
您可以使用 in 来实现这一点RecyclerView.ItemDecoration
,getItemOffsets()
以适当地偏移第一项和最后一项。
检索给定项目的任何偏移量。的每个字段
outRect
指定项目视图应插入的像素数,类似于填充或边距。默认实现将 outRect 的边界设置为 0 并返回。如果需要访问Adapter获取额外的数据,可以调用
getChildAdapterPosition(View)
获取View的adapter位置。
您可能需要使用项目的混乱尺寸RecyclerView
以及其他。但是这些信息无论如何都可以使用。
这个解决方案的问题是第一个和最后一个项目永远不会水平居中作为选择。
这可能是因为您的 RecycleView 负责在其布局范围内准确显示数据集中的项目数。
在您提供的示例图像中,您可以通过在数据集的第一个和最后一个位置添加“占位符”项来实现该效果。这样,您可以让一个不可见的项目占据第一个插槽,从而抵消您想要居中的项目。
此占位符项目不应响应触摸事件,并且不应干扰对其他项目的点击事件的处理(特别是位置处理)。
您将不得不修改您的适配器getItemCount
,也许getItemType
.
只需添加填充RecyclerView
并添加clipToPadding=false
,它只会影响末端的项目。
我最终在我的项目中实现了这个实现。您可以在构造函数中传递不同的维度来设置项目之间的间距。正如我在课堂上的 KDoc 中所写,它将添加(total parent space - child width) / 2
到第一个项目的左侧和最后一个项目的右侧,以使第一个和最后一个项目居中。
import android.graphics.Rect
import android.view.View
import androidx.annotation.DimenRes
import androidx.recyclerview.widget.OrientationHelper
import androidx.recyclerview.widget.RecyclerView
/**
* Adds (total parent space - child width) / 2 to the left of first and to the right of last item (in order to center first and last items),
* and [spacing] between items.
*/
internal class OffsetItemDecoration constructor(
@DimenRes private val spacing: Int,
) : RecyclerView.ItemDecoration() {
override fun getItemOffsets(
outRect: Rect,
view: View,
parent: RecyclerView,
state: RecyclerView.State,
) {
val itemPosition: Int = parent.getChildAdapterPosition(view)
if (itemPosition == RecyclerView.NO_POSITION) return
val spacingPixelSize: Int = parent.context.resources.getDimensionPixelSize(spacing)
when (itemPosition) {
0 ->
outRect.set(getOffsetPixelSize(parent, view), 0, spacingPixelSize / 2, 0)
parent.adapter!!.itemCount - 1 ->
outRect.set(spacingPixelSize / 2, 0, getOffsetPixelSize(parent, view), 0)
else ->
outRect.set(spacingPixelSize / 2, 0, spacingPixelSize / 2, 0)
}
}
private fun getOffsetPixelSize(parent: RecyclerView, view: View): Int {
val orientationHelper = OrientationHelper.createHorizontalHelper(parent.layoutManager)
return (orientationHelper.totalSpace - view.layoutParams.width) / 2
}
}
@IS 答案的改进,它 100% 的时间都有效,并且很容易实现,没有任何故障动画。首先,我们必须使用PagerSnapHelper()
像滚动这样的视图寻呼机。要使项目居中,您需要在 recyclerView 上添加一个大填充,然后剪辑到填充。然后使用自定义LinearSmoothScroller
来平稳地居中您的项目。要将项目居中加载,只需使用平滑滚动到位置 0。下面是代码
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_selection"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginLeft="30dp"
android:layout_marginRight="30dp"
android:paddingTop="5dp"
android:paddingBottom="5dp"
android:paddingLeft="150dp"
android:paddingRight="150dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/text_selection_alert"
app:layout_constraintBottom_toBottomOf="@+id/guideline_1"
android:clipToPadding="false"
android:background="@drawable/bg_stat"/>
在代码中(在 C# 中)
RecyclerView.LayoutManager lm = new LinearLayoutManager(Context, LinearLayoutManager.Horizontal, false);
recycler_selection = view.FindViewById<RecyclerView>(Resource.Id.recycler_selection);
recycler_selection.SetLayoutManager(new LinearLayoutManager(Context, LinearLayoutManager.Horizontal, false));
// <Set Adapter to the Recycler>
RecyclerView.SmoothScroller smoothScroller = new CenterScroller(recycler_selection.Context);
SnapHelper helper = new PagerSnapHelper();
helper.AttachToRecyclerView(recycler_selection);
smoothScroller.TargetPosition = 0;
lm.StartSmoothScroll(smoothScroller);
public class CenterScroller : LinearSmoothScroller
{
float MILLISECONDS_PER_INCH = 350f;
public CenterScroller(Context context) : base(context)
{
}
public override int CalculateDtToFit(int viewStart, int viewEnd, int boxStart, int boxEnd, int snapPreference)
{
return (boxStart + (boxEnd - boxStart) / 2) - (viewStart + (viewEnd - viewStart) / 2);
}
protected override float CalculateSpeedPerPixel(DisplayMetrics displayMetrics)
{
return MILLISECONDS_PER_INCH / displayMetrics.Xdpi;
}
}