1 以下的场景都是,使用viewpager2实现了抖音视频切换播放的场景逻辑
需求是 要求观看到某一集视频要求该视频必须完整看完,才能切换到下一集视频。
此刻 我们必须将viewpager2切换到当前的fragment进行上滑拦截,或者上滑拦截
2 大家通常的用法是重写viewpager2,但是 viewpager2 是final类型,禁止重写。我们只能另寻方案
3 可能大家会觉得比较简单,但是你测试的时候会发现,如果上划一下段距离,在下拉 必然可以拉倒下一个item,拦截事件只有在当前的item在屏幕底部的时候有效,有时候就无法拦截,这个很烦躁。
4 解决方法是 它本身是用了recycleview,你可以把他当成这个。也就是说 我们需要监听每一个recycleview的item的 touch事件,进行实践拦截。
5 上代码
1
override fun onStart() {
super.onStart()
setScroll()
}
private fun setScroll() {
// Initialize the NoSwipeItemTouchListener with default settings
noSwipeListener = NoSwipeItemTouchListener(
currentpostion,
requireContext(),
disableUpScroll = false,
disableDownScroll = false
)
touchInterceptor = ViewPagerTouchInterceptor(getViewPager())
// touchInterceptor.addTouchInterceptorToViewPager(noSwipeListener)
// 上划和下滑都可以滑动
setVerticalScroll(true, true)
}
// 设置是否可以上划或者下滑 false 不可以滑动 true 可以滑动
fun setVerticalScroll(up: Boolean, down: Boolean) {
// Remove existing listener
touchInterceptor?.removeTouchInterceptorFromViewPager()
// Create a new listener with updated settings
noSwipeListener = NoSwipeItemTouchListener(
currentpostion,
requireContext(),
disableUpScroll = up,
disableDownScroll = down
)
touchInterceptor.addTouchInterceptorToViewPager(noSwipeListener)
}
override fun onDestroy() {
super.onDestroy()
RecrodTypeManager.setUserFeed("play")
touchInterceptor?.removeTouchInterceptorFromViewPager()
touchInterceptor == null
}
2 拦截器,重点就是 move方法里的,我要获取 rv.scrollToPosition(position)
,这个方法在你向下滑动后,如果突然向上滑动,我们要进行拦截,不然此时快速切换,是可以滑动到下一个item的,我们要滑动回当前位置。这个是重点
class NoSwipeItemTouchListener(
private val position: Int,
context: Context,
private val disableUpScroll: Boolean = false,
private val disableDownScroll: Boolean = false
) : RecyclerView.OnItemTouchListener {
// private var startY = 0f
private val threshold = 5 // 滑动阈值,根据需要调整
private var startX = 0f
private var startY = 0f
private var lastX = 0f
private var lastY = 0f
private var diffY = 0f
override fun onTouchEvent(rv: RecyclerView, e: MotionEvent) {}
override fun onInterceptTouchEvent(rv: RecyclerView, event: MotionEvent): Boolean {
when (event.action) {
MotionEvent.ACTION_DOWN -> {
// startY = e.y
startX = event.x
startY = event.y
lastX = startX
lastY = startY
}
MotionEvent.ACTION_MOVE -> {
val currentX = event.x
val currentY = event.y
val diffX = currentX - lastX
diffY = currentY - lastY
if (Math.abs(diffX) > threshold || Math.abs(diffY) > threshold) {
if (Math.abs(diffX) > Math.abs(diffY)) {
// 左右滑动
if (diffX > 0) {
onSwipeRight()
} else {
onSwipeLeft()
}
} else {
// 上下滑动
if (diffY > 0) {
// LogUtil.d("diffY", "diffY: diffY")
//如果向上滑动禁止了 则拦截这个事件 ,并且回到原位
if (!disableUpScroll) {
if (diffY<-5){
rv.scrollToPosition(position)
LogUtil.d("scrollToPosition", "scrollToPosition")
}
return true
}
}
}
// 更新lastX和lastY以适应连续滑动
lastX = currentX
lastY = currentY
}
}
MotionEvent.ACTION_UP,MotionEvent.ACTION_CANCEL -> {
// 结束时重置状态
startX = 0f
startY = 0f
lastX = 0f
lastY = 0f
}
}
return false
}
private fun onSwipeRight() {
LogUtil.d("SwipeDirection", "Detected right")
// 处理向右滑动逻辑
}
private fun onSwipeLeft() {
LogUtil.d("SwipeDirection", "Detected left")
// 处理向左滑动逻辑
}
private fun onSwipeUp() {
LogUtil.d("SwipeDirection", "Detected up")
// 处理向上滑动逻辑
}
private fun onSwipeDown() {
LogUtil.d("SwipeDirection", "Detected down")
// 处理向下滑动逻辑
}
override fun onRequestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {}
}
3 viewpager2 设置每一个item的监听方法
class ViewPagerTouchInterceptor(private val viewPager: ViewPager2?) {
private var recyclerView: RecyclerView? = null
private var listener: RecyclerView.OnItemTouchListener? = null
init {
recyclerView = getRecyclerViewFromViewPager(viewPager)
}
private fun getRecyclerViewFromViewPager(viewPager: ViewPager2?): RecyclerView? {
for (i in 0 until (viewPager?.childCount ?: 0)) {
val child = viewPager?.getChildAt(i)
if (child is RecyclerView) {
return child
}
}
return null
}
fun addTouchInterceptorToViewPager(listener: RecyclerView.OnItemTouchListener) {
this.listener = listener
recyclerView?.addOnItemTouchListener(listener)
}
fun removeTouchInterceptorFromViewPager() {
listener?.let {
recyclerView?.removeOnItemTouchListener(it)
}
}
}
4 里面的getviewpager是我项目里的实例,自己自行替换即可