在另一个RecyclerView中滚动一个RecyclerView自动不能正常工作



所以我有这个recyclerview,它将包含多种类型的持有人,其中一个可以是一个可滚动的水平列表的边缘到边缘的图像,正在自动滚动,并有一个当前项目的指示符。因此,为此,我使用了一个viewholder,它本身包含另一个recyclerview和一个点指示器(它本身是另一个recycler视图,所以基本上recyclerview =一个vh列表,其中一个vh = 2水平recyclerview)。

title
[A,B,C,D...]
[+ ---]
title
[A,B,C,D...]
[+ --]
title
[A,B,C,D...]
[+ --]
title
[A,B,C,D...]
[+ --]

我最里面的水平图像的recylerview是这样创建的:


class ImageAdapter : RecyclerView.Adapter<ImageVH>() {
var imageResList = mutableListOf<Int>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ImageVH(parent, viewType)
override fun onBindViewHolder(holder: ImageVH, pos: Int)
= holder.bindData(imageResList[pos % imageResList.size])
override fun getItemCount() = Int.MAX_VALUE
}
class ImageVH(v: View) : RecyclerView.ViewHolder(v) {
constructor(parent: ViewGroup, viewtype: Int) : this(
LayoutInflater.from(parent.context).inflate(R.layout.item_image, parent, false)
)
fun bindData(imageRes: Int) {
Glide.with(itemView.context).load("").error(imageRes).into(itemView.ivImage)
}
}

它基本上是在欺骗适配器,让它认为我有一百万张图片,但实际上只有几张。这就产生了一个圆形滚动的印象。

接下来,我需要一些东西来改变第二个循环视图的点指示器。为此,我进入了这个recycleview的父类,并附加了一个onScrollListener。onScrollListener给了我2个函数:onscroll和onscrollstatechange。

  • onScrolled,我决定何时改变下一个点回收视图的状态,以显示新的点。我通过线性布局管理器做到这一点。当findFirstCompletelyVisibleItemPosition为正数时,
  • onScrollStateChanged(),我运行一种递归,每当我得到状态为SCROLL_STATE_IDLE时,我发布一个处理程序,在2秒后滚动回收视图到下一个项目。2秒后,它将自动平滑滚动并再次触发相同的事件,导致处理程序再次触发相同的动作。

所以代码看起来像这样:

data class Rails(val title: String, val images: MutableList<Int>,val autoscroll:Boolean =false)
class RailsAdapter : RecyclerView.Adapter<RailVH>() {
var railsList = mutableListOf<Rails>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = RailVH(parent, viewType)
override fun onBindViewHolder(holder: RailVH, pos: Int) = holder.bindData(railsList[pos])
override fun getItemCount() = railsList.size
}
class RailVH(v: View) : RecyclerView.ViewHolder(v) {
constructor(parent: ViewGroup, viewtype: Int) : this(
LayoutInflater.from(parent.context).inflate(R.layout.item_rails, parent, false)
)
private  var autoscrollImages = false
fun bindData(rails: Rails) {
autoscrollImages = rails.autoscroll
with(itemView) {
tvTitle?.text = rails.title
rvImagers?.apply {
adapter = ImageAdapter().also {
it.imageResList = rails.images
it.notifyDataSetChanged()
}
PagerSnapHelper().attachToRecyclerView(this)
isNestedScrollingEnabled = false
onFlingListener = null
addOnScrollListener(onScrollListener)
}
}
if(autoscrollImages){
bannerChangerHandler.postDelayed(bannerChangerRunnable,bannerChangerDelayMilllis)
}
}
private val onScrollListener = object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
//super.onScrolled(recyclerView, dx, dy)
val bannerLLManager = itemView.rvImagers?.layoutManager as? LinearLayoutManager
bannerLLManager?.let { linearLayoutManager ->
val bannerCurrentPos = linearLayoutManager.findFirstCompletelyVisibleItemPosition()
if (bannerCurrentPos >= 0) {
val rvDotsDataListSize = 5
val positionInRange = bannerCurrentPos % rvDotsDataListSize
Toast.makeText(
itemView.context,
"highlight dot #$positionInRange",
Toast.LENGTH_SHORT
).show()
}
}
}
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
//super.onScrollStateChanged(recyclerView, newState)
when (newState) {
RecyclerView.SCROLL_STATE_IDLE -> {
if(autoscrollImages){
Log.e(">>a>>", "RecyclerView.SCROLL_STATE_IDLE!")
bannerChangerHandler.postDelayed(bannerChangerRunnable, bannerChangerDelayMilllis
)
}
}
RecyclerView.SCROLL_STATE_DRAGGING -> {
Log.e(">>a>>", "RecyclerView.SCROLL_STATE_DRAGGING!")
bannerChangerHandler.removeCallbacks(bannerChangerRunnable)
}
else -> {
}
}

}
}
private val bannerChangerHandler: Handler = Handler()
private val bannerChangerRunnable = Runnable {
itemView.rvImagers?.apply {
val bannerManager = layoutManager as? LinearLayoutManager
bannerManager?.let {
val bannerCurrentPos = it.findFirstCompletelyVisibleItemPosition()
smoothScrollToPosition(bannerCurrentPos + 1)
}
}
}
private var bannerChangerDelayMilllis = 2000L
}

为简洁起见,假设每当toast出现时,它将滚动第二个点指示器recyclerview。

这些在原则上似乎都是有效的,但是有时处理程序似乎会触发两次或三次,从而导致糟糕的用户体验。有时它甚至会发疯,停止显示任何日志或任何东西,只是让轨道运行得无限快,就像处理器每毫秒触发一个自动滚动运行程序。

  • 处理程序触发2-3次

有什么帮助吗?我假设在实现级别有问题,比如触发处理程序事件可以更好地处理?

更新:感谢@ADM,我让这个工作起来了。我根据我的要求进行了调整,并且不得不放弃在相反方向的圆形滚动支持,但给定的解决方案足以回答我的问题。谢谢!

Handler不是问题,这里是Runnable。你每次都在使用和发布相同的Runnable,这就是为什么它会堆积起来。您不能删除前一个呼叫,因为您没有Tag或令牌到这个延迟呼叫。看看Handler's的一些方法,比如sendMessageDelayed,这些可能会有所帮助。

经过一番思考,我认为你可以将自动滚动部分移动到SnapHelper。不是一个完整的解决方案,但我认为它会工作。您可能需要在SnapHelper中添加一些检查。试一试,然后告诉我。我还没有测试过。

class AutoPagedSnapHelper(private var autoScrollInterval: Long) : PagerSnapHelper() {
private var recyclerView: RecyclerView? = null
private var currentPage = 0
private var isHold = false
private val autoScrollRunnable = Runnable {
recyclerView?.let {
if (recyclerView?.scrollState != RecyclerView.SCROLL_STATE_DRAGGING && !isHold) {
if (it.adapter != null) {
val lastPageIndex = (recyclerView?.adapter!!.itemCount - 1)
var nextIndex: Int
nextIndex = currentPage + 1
if (currentPage == lastPageIndex) {
nextIndex = 0
}
it.post {
val linearSmoothScroller = object : LinearSmoothScroller(recyclerView?.context) {
override fun calculateSpeedPerPixel(displayMetrics: DisplayMetrics): Float {
return MILLISECONDS_PER_INCH / displayMetrics.densityDpi
}
}
linearSmoothScroller.targetPosition = nextIndex
(recyclerView?.layoutManager as LinearLayoutManager).startSmoothScroll(linearSmoothScroller)
}
}
} else {
postNextPage()
}
}
}
override fun attachToRecyclerView(recyclerView: RecyclerView?) {
super.attachToRecyclerView(recyclerView)
if (this.recyclerView === recyclerView) {
return
}
if (autoScrollInterval != 0L) {
this.recyclerView = recyclerView
this.recyclerView?.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
super.onScrollStateChanged(recyclerView, newState)
if (newState == RecyclerView.SCROLL_STATE_IDLE || newState == RecyclerView.SCROLL_STATE_SETTLING) {
val itemPosition = (recyclerView.layoutManager as LinearLayoutManager).findFirstCompletelyVisibleItemPosition()
if (itemPosition != -1) {
currentPage = itemPosition
postNextPage()
}
}
}
})
postNextPage()
recyclerView?.addOnItemTouchListener(object : RecyclerView.OnItemTouchListener {
override fun onInterceptTouchEvent(rv: RecyclerView, event: MotionEvent): Boolean {
when (event.action) {
MotionEvent.ACTION_DOWN -> {
isHold = true
}
MotionEvent.ACTION_CANCEL, MotionEvent.ACTION_UP, MotionEvent.ACTION_POINTER_UP -> {
isHold = false
}
}
return false
}
override fun onTouchEvent(rv: RecyclerView, event: MotionEvent) {}
override fun onRequestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {}
})
}
}
fun postNextPage() {
recyclerView?.handler?.removeCallbacks(autoScrollRunnable)
recyclerView?.postDelayed(autoScrollRunnable, autoScrollInterval)
}
companion object {
private const val MILLISECONDS_PER_INCH = 75f //default is 25f (bigger = slower)
}
}

这应该照顾自动更改页面。您不必在Adapter中使用scrollListener。试试吧。

最新更新