滚动 Android RecyclerView 并控制屏幕上的确切位置
Scroll an Android RecyclerView and control the exact location on screen
我正在寻找一种以编程方式缓慢滚动 RecyclerView 以便将某个元素 targetPosition 恰好放在屏幕中间的方法。请注意,我在 RecylerView 中的所有项目在设计上都具有相同的高度。 RecyclerView 是垂直的。我正在使用 Kotlin 和 AndroidX
编程
我试过:
smoothScrollToPosition(targetPosition)
它滚动缓慢(我也可以通过扩展 LinearLayoutManager 和覆盖 calculateSpeedPerPixel() 来控制速度 - 参见 ),但是我无法控制列表项在滚动后的屏幕。我所知道的是它将在屏幕上完全可见。
我试过:
scrollToX(0, targetPosition * itemHeight - screenHeight / 2)
它给我错误信息:"W/RecyclerView: RecyclerView does not support scrolling to an absolute position. Use scrollToPosition instead"
我也曾尝试用包含所有子项的 LinearLayoutManager 替换 RecyclerView,并在视图中转换 LinearLayoutManager,但最初我没有让子项在屏幕外绘制。
这个问题有解决办法吗?
您可以根据您的实际目标位置和可见项的数量来计算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)
谢谢@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)
}
}
我正在寻找一种以编程方式缓慢滚动 RecyclerView 以便将某个元素 targetPosition 恰好放在屏幕中间的方法。请注意,我在 RecylerView 中的所有项目在设计上都具有相同的高度。 RecyclerView 是垂直的。我正在使用 Kotlin 和 AndroidX
编程我试过:
smoothScrollToPosition(targetPosition)
它滚动缓慢(我也可以通过扩展 LinearLayoutManager 和覆盖 calculateSpeedPerPixel() 来控制速度 - 参见
我试过:
scrollToX(0, targetPosition * itemHeight - screenHeight / 2)
它给我错误信息:"W/RecyclerView: RecyclerView does not support scrolling to an absolute position. Use scrollToPosition instead"
我也曾尝试用包含所有子项的 LinearLayoutManager 替换 RecyclerView,并在视图中转换 LinearLayoutManager,但最初我没有让子项在屏幕外绘制。
这个问题有解决办法吗?
您可以根据您的实际目标位置和可见项的数量来计算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)
谢谢@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)
}
}