gpt4 book ai didi

android - 使用 LinearSnapHelper 在 recyclerview 中捕捉第一个和最后一个项目的问题

转载 作者:太空宇宙 更新时间:2023-11-03 12:44:20 27 4
gpt4 key购买 nike

我有 recyclerView 可以水平滚动。每个 View 都将捕捉到显示的中心。为了实现这一点,我使用了 LinearSnapHelper。这个工具工作得很好。

问题出在回收站 View 中的lastfirst 项目上。当您滚动到开头时,这两个 未对齐到中心。如果您在开始滚动之前检查 recyclerview 状态,您可以看到第一个项目位于屏幕中央的正确位置。我通过添加我的自定义 ItemOffsetDecoration 实现了这一点。我根据显示器和 View 本身的宽度为最后一个和第一个 View 添加了额外的填充,因此它会将它定位在中间。

问题是,如果您滚动 recyclerview 并将其滚动回开头或结尾,这些 View 不会对齐到中间。看起来 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)
}
}
}

应用中问题的简短预览(我还必须修复一些动画错误 :D):

enter image description here

最佳答案

LinearSnapHelper 在关联 View 的测量中包含项目装饰,因此您的第一个和最后一个 View 永远不会真正居中,因为测量的 View 大小延伸到 RecyclerView 的左侧或右侧

您没有发布您的 XML,因此您可能已经执行了如下操作。使开始和结束 View 正确居中的典型方法是向 RecyclerView 添加填充并指定 android:clipToPadding="false"。这与从 FAB 等移动端 View 的技术相同。

<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 必须根据您的应用和布局进行调整,您不需要项目装饰,移动 View 是它的唯一目的。

关于android - 使用 LinearSnapHelper 在 recyclerview 中捕捉第一个和最后一个项目的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51514232/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com