Android RecycleView 如何禁用手动滚动但允许单击项目
Android RecycleView how to disable manual scroll but allow item clicked
我正在研究一个想法,让 RecyclerView 自动滚动,但允许用户在不停止滚动的情况下单击项目。
首先,我创建了一个自定义 LayoutManager 来禁用手动滚动,同时更改滚动到某个位置的速度
class CustomLayoutManager(context: Context, countOfColumns: Int) :
GridLayoutManager(context, countOfColumns) {
// Custom smooth scroller
private val smoothScroller = object : LinearSmoothScroller(context) {
override fun calculateSpeedPerPixel(displayMetrics: DisplayMetrics): Float =
500f / displayMetrics.densityDpi
}
// Disable manual scroll
override fun canScrollVertically(): Boolean = false
// Using custom smooth scroller to control the duration of smooth scroll to a certain position
override fun smoothScrollToPosition(
recyclerView: RecyclerView,
state: RecyclerView.State?,
position: Int
) {
smoothScroller.targetPosition = position
startSmoothScroll(smoothScroller)
}
}
然后我为 RecyclerView 做初始工作,并在 1 秒后开始平滑滚动
viewBinding.list.apply {
// initial recycler view
setHasFixedSize(true)
customLayoutManager = CustomLayoutManager(context = context, countOfColumns = 2)
layoutManager = customLayoutManager
// data list
val dataList = mutableListOf<TestModel>()
repeat(times = 100) { dataList.add(TestModel(position = it, clicked = false)) }
// adapter
testAdapter =
TestAdapter(clickListener = { testAdapter.changeVhColorByPosition(position = it) })
adapter = testAdapter
testAdapter.submitList(dataList)
// automatically scroll after 1 sec
postDelayed({ smoothScrollToPosition(dataList.lastIndex) }, 1000)
}
一切都按照我的预期进行,直到我发现当我点击 RecycelerView 上的任何项目时自动滚动停止,clickListener
触发时的功能只是更改 [=15= 中视图持有者的背景颜色]
fun changeVhColor(position: Int) {
position
.takeIf { it in 0..itemCount }
?.also { getItem(it).clicked = true }
?.also { notifyItemChanged(it) }
}
这里是录屏screen recording
我遇到的问题
- 当我点击 ReycelerView 上的任何项目时自动滚动停止
- 第一次点击停止滚动,第二次点击触发
clickListener
,但我希望通过一次点击触发 clickListener
谁能告诉我如何解决这个问题?提前致谢。
这里发生了很多事情。您应该怀疑 RecyclerView 的触摸处理以及对 notifyItemChanged(it)
的调用,但我相信 RecyclerView 正在运行正确。您可以考虑覆盖 RecyclerView 中的触摸代码以使其执行您想要的操作 - 假设您可以访问并覆盖它。
另一种方法是用另一个透明视图覆盖 RecyclerView 并捕获透明视图上的所有触摸。然后,您可以为与 RecyclerView 交互的透明视图编写代码,以满足您的目标。这也很棘手,您将不得不对 RecyclerView 进行更改,因为它会在滚动发生时不断布局视图。由于您有自己的布局管理器,如果您在滚动发生时将更改排队pre-layout,这可能会更容易。
尝试了几种方法后,发现让recycler视图自动滚动的关键是override onInterceptTouchEvent
示例
class MyRecyclerView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyle: Int = 0
) : RecyclerView(context, attrs, defStyle) {
override fun onInterceptTouchEvent(e: MotionEvent?): Boolean = false
}
这将使自定义 RecyclerView 忽略所有触摸事件
我正在研究一个想法,让 RecyclerView 自动滚动,但允许用户在不停止滚动的情况下单击项目。
首先,我创建了一个自定义 LayoutManager 来禁用手动滚动,同时更改滚动到某个位置的速度
class CustomLayoutManager(context: Context, countOfColumns: Int) :
GridLayoutManager(context, countOfColumns) {
// Custom smooth scroller
private val smoothScroller = object : LinearSmoothScroller(context) {
override fun calculateSpeedPerPixel(displayMetrics: DisplayMetrics): Float =
500f / displayMetrics.densityDpi
}
// Disable manual scroll
override fun canScrollVertically(): Boolean = false
// Using custom smooth scroller to control the duration of smooth scroll to a certain position
override fun smoothScrollToPosition(
recyclerView: RecyclerView,
state: RecyclerView.State?,
position: Int
) {
smoothScroller.targetPosition = position
startSmoothScroll(smoothScroller)
}
}
然后我为 RecyclerView 做初始工作,并在 1 秒后开始平滑滚动
viewBinding.list.apply {
// initial recycler view
setHasFixedSize(true)
customLayoutManager = CustomLayoutManager(context = context, countOfColumns = 2)
layoutManager = customLayoutManager
// data list
val dataList = mutableListOf<TestModel>()
repeat(times = 100) { dataList.add(TestModel(position = it, clicked = false)) }
// adapter
testAdapter =
TestAdapter(clickListener = { testAdapter.changeVhColorByPosition(position = it) })
adapter = testAdapter
testAdapter.submitList(dataList)
// automatically scroll after 1 sec
postDelayed({ smoothScrollToPosition(dataList.lastIndex) }, 1000)
}
一切都按照我的预期进行,直到我发现当我点击 RecycelerView 上的任何项目时自动滚动停止,clickListener
触发时的功能只是更改 [=15= 中视图持有者的背景颜色]
fun changeVhColor(position: Int) {
position
.takeIf { it in 0..itemCount }
?.also { getItem(it).clicked = true }
?.also { notifyItemChanged(it) }
}
这里是录屏screen recording
我遇到的问题
- 当我点击 ReycelerView 上的任何项目时自动滚动停止
- 第一次点击停止滚动,第二次点击触发
clickListener
,但我希望通过一次点击触发clickListener
谁能告诉我如何解决这个问题?提前致谢。
这里发生了很多事情。您应该怀疑 RecyclerView 的触摸处理以及对 notifyItemChanged(it)
的调用,但我相信 RecyclerView 正在运行正确。您可以考虑覆盖 RecyclerView 中的触摸代码以使其执行您想要的操作 - 假设您可以访问并覆盖它。
另一种方法是用另一个透明视图覆盖 RecyclerView 并捕获透明视图上的所有触摸。然后,您可以为与 RecyclerView 交互的透明视图编写代码,以满足您的目标。这也很棘手,您将不得不对 RecyclerView 进行更改,因为它会在滚动发生时不断布局视图。由于您有自己的布局管理器,如果您在滚动发生时将更改排队pre-layout,这可能会更容易。
尝试了几种方法后,发现让recycler视图自动滚动的关键是override onInterceptTouchEvent
示例
class MyRecyclerView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyle: Int = 0
) : RecyclerView(context, attrs, defStyle) {
override fun onInterceptTouchEvent(e: MotionEvent?): Boolean = false
}
这将使自定义 RecyclerView 忽略所有触摸事件