我正在寻找一种以编程方式缓慢滚动RecyclerView的方法,以便将某个元素targetPosition恰好置于屏幕中间。请注意,我在RecylerView中的所有项目在设计上都具有相同的高度。 RecyclerView是垂直的。我正在用Kotlin和AndroidX编程
我尝试过:
smoothScrollToPosition(targetPosition)
它确实进行了缓慢的滚动(我也可以通过扩展LinearLayoutManager并覆盖calculateSpeedPerPixel()来控制速度)(请参阅How can i control the scrolling speed of recyclerView.smoothScrollToPosition(position)),但是在此之后,我无法控制列表项在屏幕上的确切位置滚动。我所知道的是它将在屏幕上完全可见。
我尝试过:
scrollToX(0, targetPosition * itemHeight - screenHeight / 2)
它给我错误消息:“ W / RecyclerView:RecyclerView不支持滚动到绝对位置。请改用scrollToPosition”
我还尝试过用LinearLayoutManager替换RecyclerView,该对象包含所有项作为子项,并在视图中平移LinearLayoutManager,但最初没有让子项在屏幕外绘制。
这个问题有解决方案吗?
答案 0 :(得分:1)
您可以根据实际目标位置和可见项目的数量来计算smoothScrollToPosition
的targetPosition。
有关如何执行此操作的快速POC:
val scrollToPosition = 50
val layoutManager = recyclerView.layoutManager as LinearLayoutManager
val firstPosition = layoutManager.findFirstVisibleItemPosition()
val lastPosition = layoutManager.findLastVisibleItemPosition()
val visibleItems = lastPosition - firstPosition + 1
if (firstPosition < scrollToPosition) {
recyclerView.smoothScrollToPosition(scrollToPosition + (visibleItems / 2))
} else {
recyclerView.smoothScrollToPosition(scrollToPosition - (visibleItems / 2))
}
如果您想获得更精确的结果,使该项恰好位于屏幕的中间,则可以使用该项的高度(自固定状态)和RecyclerView的高度,然后计算要滚动的偏移量。并致电:
recyclerView.scrollBy(dx, dy)
或者:
recyclerView.smoothScrollBy(dx, dy)
答案 1 :(得分:0)
谢谢@Bob。我错过了scrollBy()。按照您的建议,以下是对我有用的代码。
class RecyclerViewFixedItemSize : RecyclerView {
var itemFixedSize : Int = 0
constructor(context: Context, attrs: AttributeSet?, defStyle: Int) : super(context, attrs, defStyle) {
}
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
}
constructor(context: Context) : super(context) {
}
fun smoothScrollToPositionCentered(position: Int) {
// Find the fixed item size - once for all
if (itemFixedSize == 0) {
val ll = layoutManager as LinearLayoutManager
val fp = ll.findFirstCompletelyVisibleItemPosition()
val fv = ll.getChildAt(fp)
itemFixedSize = fv!!.height
}
// find the recycler view position and screen coordinates of the first item (partially) visible on screen
val ll = layoutManager as LinearLayoutManagerFixedItemSize
val fp = ll.findFirstVisibleItemPosition()
val fv = ll.getChildAt(0)
// find the middle of the recycler view
val dyrv = (top - bottom ) / 2
// compute the number of pixels to scroll to get the view position in the center
val dy = (position - fp) * itemFixedSize + dyrv + fv!!.top + itemFixedSize / 2
smoothScrollBy(0, dy)
}
}