某些场景或者框架限制的情况下,使用了 Scrollview 嵌套 Recyclerview 布局

此时会有问题

1、滑动时 Recyclerview 被禁用了滑动事件,无法监听滑动事件

2、Recyclerview 被重新测量,item充满全屏,导致无法监听生命周期

还有场景是没有任何嵌套列表,只有 ScrollView

如果这时候需要在滑动停止时处理一些操作,比如视频自动播放,这种时候只能自己去实现,无法跟Recyclerview一样监听到滑动停止操作

因为 ScrollView 滑动手指抬起时,会有惯性在滑动一段距离

需要借助系统监听 setOnScrollChangeListener ,只要列表处于滑动中,它就会触发回调,按照这个思路,基于嵌套 Recyclerview 为例子,有个简单的实现方案

1、在滑动开始时开启一个循环,循环内读取当前列表的滑动值 scrollY

2、记录下当前 scrollY,用于下次触发时对比

3、监听停止时再次触发循环,此时 scrollY 是一样的,这时候就表示 ScrollView 已经停止

private class WeakReferenceHandler(tag: ScrollStatusListenerUtils): Handler() {
            private val scrollTag = WeakReference(tag)
            override fun handleMessage(msg: Message) {
                super.handleMessage(msg)
                scrollTag.get()?.apply {
                    val scrollView = msg.obj as ScrollView?
                    if (lastY == (scrollView?.scrollY ?: 0)) {
                        stopScroll?.invoke(lastY)
                        lastY = 0
                        removeMessages(SCROLL_MSG_START)
                        isScroll = false
                    } else {
                        lastY = scrollView?.scrollY ?: 0
                        sendMsg(scrollView)
                    }
                }
            }
        }

这里会有个循环发送,使用 handler 循环,当开启滑动后,每300毫秒触发一次,等结束时循环内 scrollY 会跟 lastY 一致,此时滑动停止

并且你反复触发多次滑动时不影响监听

 

可以看到日志,我最后一次监听的滑动坐标是 1211,在列表中处于第3个位置,也就是可见 position

然后在滑动结束时 removeMessages 当前消息,在活动销毁时释放内存 removeCallbacksAndMessages

为了防止 Handler 内存泄漏,需要使用 WeakReference

在滑动停止时,通过 ScrollView 获取到嵌套的 Recyclerview

同时通过 layoutManager 拿到所有 Recyclerview itemRootView,通过停止时的滑动值 scrollY 跟 当前 itemRootView 的 top 值对比,大于当前 top 值就是当前的可见 item

得到当前可见 item 后,就可以执行播放视频操作了,然后记录当前播放下标,在下次滑动停止时判断是否一致,如果一致表示还停在当前视频

package com.frogsing.common.utils

import android.os.Handler
import android.os.Message
import android.widget.ScrollView
import java.lang.ref.WeakReference

class ScrollStatusListenerUtils {

    private var isScroll = false
    private var lastY = 0
    private var stopScroll: ((Int) -> Unit)? = null

    private object SingleInstance {
        val instance = ScrollStatusListenerUtils()
    }

    companion object {
        private const val SCROLL_MSG_START = 1
        private class WeakReferenceHandler(tag: ScrollStatusListenerUtils): Handler() {
            private val scrollTag = WeakReference(tag)
            override fun handleMessage(msg: Message) {
                super.handleMessage(msg)
                scrollTag.get()?.apply {
                    val scrollView = msg.obj as ScrollView?
                    if (lastY == (scrollView?.scrollY ?: 0)) {
                        stopScroll?.invoke(lastY)
                        lastY = 0
                        removeMessages(SCROLL_MSG_START)
                        isScroll = false
                    } else {
                        lastY = scrollView?.scrollY ?: 0
                        sendMsg(scrollView)
                    }
                }
            }
        }

        fun instance(): ScrollStatusListenerUtils {
            return SingleInstance.instance
        }
    }

    private val handler = WeakReferenceHandler(this)

    fun start(scrollView: ScrollView?) {
        if (!isScroll) {
            isScroll = true
            sendMsg(scrollView)
        }
    }

    fun sendMsg(scrollView: ScrollView?) {
        val msg = handler.obtainMessage(SCROLL_MSG_START)
        msg.obj = scrollView
        handler.sendMessageDelayed(msg, 300L)
    }

    fun setStopScrollListener(stopScroll: (Int) -> Unit) {
        this.stopScroll = stopScroll
    }

    fun clear() {
        lastY = 0
        isScroll = false
        if (handler.hasMessages(SCROLL_MSG_START)) {
            handler.removeMessages(SCROLL_MSG_START)
        }
        handler.removeCallbacksAndMessages(null)
    }

}
ScrollStatusListenerUtils

使用时需要注意版本判断,因为 setOnScrollChangeListener 是在6.0才出

如果封装成通用的播放工具,最好添加生命周期监听 LifecycleObserver,控制视频恢复,播放,暂停,释放等操作

 

 

 

来源Scrollview实现滑动停止监听,Scrollview嵌套Recyclerview获取滑动停止时当前可见position - 翻滚的咸鱼 - 博客园 (cnblogs.com)

posted on 2023-01-17 15:06  翻滚的咸鱼  阅读(1245)  评论(0编辑  收藏  举报