簡體   English   中英

使用LinearSnapHelper在recyclelerview中捕捉第一個和最后一個項目的問題

[英]Issue with snapping of first and last item in recyclerview using LinearSnapHelper

我有recyclerView ,可以水平方向滾動。 每個視圖都會捕捉到顯示屏的中心。 為了實現這一點,我使用了LinearSnapHelper。 這個工具工作得很好。

問題在於Recyclerview中的最后一項第一項。 滾動到開頭時,這兩個not snapped to the center 如果在滾動發生之前檢查開始時的recyclerview狀態,則可以看到第一個項目位於屏幕中心的正確位置。 我通過添加自定義ItemOffsetDecoration實現了這一點。 我根據顯示器的寬度和視圖本身為最后和第一個視圖添加了額外的填充,因此它將它放在中間位置。

問題是,如果您滾動Recyclerview並將其滾動回到開頭或結尾,那么這些視圖不會被捕捉到中間。 看起來LinearSnapHelper無法將其檢測為快照。

RecyclerViewInit:

timelineSnapHelper = LinearSnapHelper()
    timelineViewManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
    timelineViewAdapter = TimelineListAdapter(timelineViewManager, timelineList, this)
    timelineOffsetDecoration = ItemOffsetDecoration(context!!, 32, 45)

    timelineRecyclerView = view.findViewById<RecyclerView>(R.id.timeline_recycler_view).apply {
        layoutManager = timelineViewManager
        adapter = timelineViewAdapter
        addItemDecoration(timelineOffsetDecoration)
        setHasFixedSize(true)
    }

    timelineSnapHelper.attachToRecyclerView(timelineRecyclerView)

    timelineRecyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
        override fun onScrollStateChanged(recyclerView: RecyclerView?, newState: Int) {
            if (newState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE) {
                val centerView = timelineSnapHelper.findSnapView(timelineRecyclerView.layoutManager)
                val anim = AnimationUtils.loadAnimation(context, R.anim.scale_timeline_start)
                centerView!!.startAnimation(anim)
                anim.fillAfter = true
                lastSnappedTime = centerView
            } else if (lastSnappedTime != null){
                lastSnappedTime = null
            }

            if(newState == AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL && lastSnappedTime != null){
                val anim = AnimationUtils.loadAnimation(context, R.anim.scale_timeline_end)
                lastSnappedTime!!.startAnimation(anim)
                anim.fillAfter = true
            }
        }
    })

自定義項目裝飾:

class ItemOffsetDecoration(private val context: Context, private val edgePadding: Int, private var viewWidth: Int): RecyclerView.ItemDecoration() {


override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State?) {
    super.getItemOffsets(outRect, view, parent, state)

    val itemCount = state!!.itemCount


    val itemPosition = parent.getChildAdapterPosition(view)
    // no position, leave it alone
    if (itemPosition == RecyclerView.NO_POSITION) {
        return
    }

    val displayMetrics = context.resources.displayMetrics
    val displayWidth: Int = displayMetrics.widthPixels
    val viewPixelWidth: Int = (viewWidth * (displayMetrics.densityDpi / 160f)).toInt()
    val startEndPadding: Int = (displayWidth - viewPixelWidth) / 2

    // first item
    if (itemPosition == 0) {
        outRect.set(startEndPadding, edgePadding, edgePadding, edgePadding)
    }
    // last item
    else if (itemCount > 0 && itemPosition == itemCount - 1) {
        outRect.set(edgePadding, edgePadding, startEndPadding, edgePadding)
    }
    // every other item
    else {
        outRect.set(edgePadding, edgePadding, edgePadding, edgePadding)
    }
 }
}

在應用程序中的問題的簡短預覽( I have to fix some animation bugs yet :D ):

在此輸入圖像描述

LinearSnapHelper在相關視圖的測量中包含項目裝飾,因此您的第一個和最后一個視圖永遠不會真正居中,因為測量的視圖大小延伸到RecyclerView的左側或右側。

您沒有發布XML,因此您可能已經執行了以下操作。 使開始和結束視圖正確居中的典型方法是向RecyclerView添加填充並指定android:clipToPadding="false" 這與從FAB等移動結束視圖的技術相同。

<android.support.v7.widget.RecyclerView
    android:id="@+id/recyclerView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:clipToPadding="false"
    android:paddingStart="35dp"
    android:paddingEnd="35dp"/>

這里35dp必須根據您的應用和布局進行調整,您不需要項目裝飾移動視圖是其唯一目的。

暫無
暫無

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

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