StackOverflow遇到这样的问题,但是到目前为止,绝对没有解决方案可以100%起作用。
我尝试了以下解决方案:
RecyclerView ItemDecoration-如何为每个viewHolder绘制不同的宽度分隔线?
第一个项目中心在RecyclerView中的SnapHelper中对齐
LinearSnapHelper不能捕捉RecyclerView的边缘项目
如何将RecyclerView捕捉到中心并在“选择”中心的同时滚动到所有项目?
如何在水平RecyclerView中捕捉到LinearSnapHelper的特定位置?
但是,每次第一个项目都无法正确居中。
我正在使用的示例代码
recyclerView.addItemDecoration(new 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 count = state.getItemCount();
final int position = parent.getChildAdapterPosition(view);
if (position == 0 || position == count - 1) {
int offset = (int) (parent.getWidth() * 0.5f - view.getWidth() * 0.5f);
if (position == 0) {
setupOutRect(outRect, offset, true);
} else if (position == count - 1) {
setupOutRect(outRect, offset, false);
}
}
}
private void setupOutRect(Rect rect, int offset, boolean start) {
if (start) {
rect.left = offset;
} else {
rect.right = offset;
}
}
});
经过调查,我发现,这是因为在该时间getItemOffsets
的view.getWidth
是0,它并没有被测量呢。
我试图强制对其进行测量,但是每一次它给出的尺寸都不正确,就不会像它实际占用的尺寸那样小。
我也尝试使用该addOnGlobalLayoutListener
技巧,但到调用它的时间并具有正确的宽度时,outRect
它已经被消耗了,因此丢失了。
我不想设置任何固定的大小,因为中的项目RecyclerView
可以具有不同的大小,因此无法提前设置其填充。
我也不想添加“鬼影”项目来填充空间,并且这些内容也无法很好地实现滚动体验。
如何使它正常工作?
理想情况下,该ItemDecorator
方法看起来是最好的,但是对于第一个项目,它马上就落空了。
您也可以更改RecyclerView
自身的填充以达到此效果(只要clipToPadding
已禁用)。我们可以拦截第一个布局阶段,LayoutManager
因此即使是初次布局项目时也可以使用更新的填充:
添加此布局管理器:
open class CenterLinearLayoutManager : LinearLayoutManager {
constructor(context: Context) : super(context)
constructor(context: Context, orientation: Int, reverseLayout: Boolean) : super(context, orientation, reverseLayout)
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes)
private lateinit var recyclerView: RecyclerView
override fun onLayoutChildren(recycler: RecyclerView.Recycler, state: RecyclerView.State) {
// always measure first item, its size determines starting offset
// this must be done before super.onLayoutChildren
if (childCount == 0 && state.itemCount > 0) {
val firstChild = recycler.getViewForPosition(0)
measureChildWithMargins(firstChild, 0, 0)
recycler.recycleView(firstChild)
}
super.onLayoutChildren(recycler, state)
}
override fun measureChildWithMargins(child: View, widthUsed: Int, heightUsed: Int) {
val lp = (child.layoutParams as RecyclerView.LayoutParams).absoluteAdapterPosition
super.measureChildWithMargins(child, widthUsed, heightUsed)
if (lp != 0 && lp != itemCount - 1) return
// after determining first and/or last items size use it to alter host padding
when (orientation) {
HORIZONTAL -> {
val hPadding = ((width - child.measuredWidth) / 2).coerceAtLeast(0)
if (!reverseLayout) {
if (lp == 0) recyclerView.updatePaddingRelative(start = hPadding)
if (lp == itemCount - 1) recyclerView.updatePaddingRelative(end = hPadding)
} else {
if (lp == 0) recyclerView.updatePaddingRelative(end = hPadding)
if (lp == itemCount - 1) recyclerView.updatePaddingRelative(start = hPadding)
}
}
VERTICAL -> {
val vPadding = ((height - child.measuredHeight) / 2).coerceAtLeast(0)
if (!reverseLayout) {
if (lp == 0) recyclerView.updatePaddingRelative(top = vPadding)
if (lp == itemCount - 1) recyclerView.updatePaddingRelative(bottom = vPadding)
} else {
if (lp == 0) recyclerView.updatePaddingRelative(bottom = vPadding)
if (lp == itemCount - 1) recyclerView.updatePaddingRelative(top = vPadding)
}
}
}
}
// capture host recyclerview
override fun onAttachedToWindow(view: RecyclerView) {
recyclerView = view
super.onAttachedToWindow(view)
}
}
然后将其用于您的RecyclerView:
recyclerView.layoutManager = CenterLinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)
recyclerView.clipToPadding = false // disabling clip to padding is critical
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句