如何在 recyclerView 中找到锚点内部项目

How to find anchor inner item in recyclerView

我遇到了一个小问题,我需要从 recyclerView 中心可见项目中找到锚项目

请查看下图以供参考

下面是我用来从 recyclerView 中查找中心项目的代码

class CenterItemFinder(
  private val context: Context,
  private val layoutManager: LinearLayoutManager,
  private val callback: CenterItemCallback,
  private val controlState: Int
) : OnScrollListener() {
  override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
    if (controlState == ALL_STATES || newState == controlState) {
      val firstVisible = layoutManager.findFirstVisibleItemPosition()
      val lastVisible = layoutManager.findLastVisibleItemPosition()
      val itemsCount = lastVisible - firstVisible + 1
      val screenCenter = context.resources.displayMetrics.widthPixels / 2
      var minCenterOffset = Int.MAX_VALUE
      var middleItemIndex = 0
      for (index in 0 until itemsCount) {
        val listItem = layoutManager.getChildAt(index) ?: return
        val leftOffset = listItem.left
        val rightOffset = listItem.right
        val centerOffset =
          Math.abs(leftOffset - screenCenter) + Math.abs(rightOffset - screenCenter)
        if (minCenterOffset > centerOffset) {
          minCenterOffset = centerOffset
          middleItemIndex = index + firstVisible
        }
      }
      callback.scrollFinished(middleItemIndex)
    }
  }

  interface CenterItemCallback {
    fun scrollFinished(middleElement: Int)
  }

  companion object {
    const val ALL_STATES = 10
  }
}

我想在 recyclerView 中找到内部锚项目,但无法在 recyclerView 中找到准确的中心可见内部项目

我能找到 recyclerView 的中心可见项,但找不到锚点内部项

这是相同的参考视频

https://drive.google.com/file/d/1OIPq-YOFhch6xFpSZGEFZTDHhDisicDg/view?usp=sharing

想法是锚视图离中心更近:

首先获取居中item在屏幕上的x位置(即左边缘),加上item宽度得到右边缘;然后将其与屏幕的中心点进行比较,以了解哪个边缘更接近中心。

但首先,我们需要获取与居中项目关联的 ViewHolder 实例,以获取这些位置并访问基础视图。

您已经在 onScrollStateChanged() 回调中获得 RecyclerView 中居中项目 (middleItemIndex) 的位置。然后获取此位置的关联 ViewHolder 实例:

val holder =
    recyclerView.findViewHolderForAdapterPosition(middleItemIndex) as MyViewHolder // Cast that to your ViewHolder class

// Get the centered item position on the screen
val point = IntArray(2)
holder.itemView.getLocationOnScreen(point) // or getLocationInWindow(point)

val leftEdge = point[0]
val rightEdge = leftEdge + holder.itemView.width
val screenCenter = resources.displayMetrics.widthPixels / 2

val leftOffset = Math.abs(leftEdge - screenCenter)
val rightOffset = Math.abs(rightEdge - screenCenter)


// And eventually get the anchor view:
val anchorView = if (leftOffset > rightOffset) {
    // The right view is the anchor
    holder.itemView.findViewById<...>(R.id.rightItemId) // adjust rightItemId to your most right view id in the RV item

} else {
    // The left view is the anchor 
    holder.itemView.findViewById<...>(R.id.leftItemId) // adjust leftItemId to your most left view id in the RV item
}

更新

using this condition if (leftOffset > rightOffset) { i'm able to detect first and last block from recyclerview, the issue is that i'm not able to detect the center block item (the item which have ...)

您可以将居中的项目分成3等份,其中将有两条边与屏幕中心位置进行比较:

// Get the centered item x,y position on the screen
val point = IntArray(2)
holder.itemView.getLocationOnScreen(point) // or getLocationInWindow(point)

val itemWidth = holder.itemView.width

// Divide the width into 3 equal parts (two margins)
val leftMargin = point[0] + itemWidth / 3
val rightMargin = point[0] + itemWidth * 2 / 3

val anchorView =
    when {
        screenCenter > rightMargin -> {
            // The anchor is the right item
            holder.itemView.findViewById<..>(R.id.rightItemId) // adjust rightItemId to the most right view id in the RV item
        }
        screenCenter > leftMargin -> {
            // The anchor is the middle item
            holder.itemView.findViewById<..>(R.id.middleItemId) // adjust rightItemId to the middle view id in the RV item
        }
        else -> {
            // The anchor is the left item
            holder.itemView.findViewById<..>(R.id.leftItemId) // adjust rightItemId to the most left view id in the RV item

        }
    }