簡體   English   中英

水平居中 RecyclerView 的第一項

[英]Horizontally center first item of RecyclerView

我想使用RecyclerView來模擬MultiViewPager的行為,特別是我想讓所選項目位於屏幕中央,包括第一個和最后一個元素

正如您在此圖像中看到的,第一項居中,這將是我的預期結果。 預期結果

我所做的是使用水平LinearLayoutManagerLinearSnapHelper設置RecyclerView 這個解決方案的問題是第一個和最后一個項目永遠不會作為選擇水平居中。 我應該切換我的代碼以便它使用MultiViewPager還是可以利用RecyclerView獲得類似的結果?

您可以使用getItemOffsets()RecyclerView.ItemDecoration來實現這一點,以適當地偏移第一個和最后一個項目。

檢索給定項目的任何偏移量。 outRect每個字段指定項目視圖應該插入的像素數,類似於填充或邊距。 默認實現將 outRect 的邊界設置為 0 並返回。

如果需要訪問Adapter獲取額外的數據,可以調用getChildAdapterPosition(View)獲取getChildAdapterPosition(View)的Adapter位置。

您可能還需要使用項目的大小和RecyclerView 但是這些信息無論如何都可以使用。

這個解決方案的問題是第一個和最后一個項目永遠不會作為選擇水平居中。

這可能是因為您的 RecycleView 負責在其布局范圍內准確顯示數據集內的項目數量。

在您提供的示例圖像中,您可以通過在數據集的第一個和最后一個位置添加“占位符”項來實現該效果。 這樣,您可以讓一個不可見的項目占據第一個插槽,從而抵消您想要居中的項目。

此占位符項不應響應觸摸事件,也不應干擾其他項上單擊事件的處理(特別是位置處理)。

您將不得不修改您的適配器getItemCountgetItemType

只需在RecyclerView上添加 padding 並添加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;
        }
    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM