fix: 下拉手势改用RecyclerView.OnItemTouchListener

SwipeDownLayout的onInterceptTouchEvent方案仍无法检测到下拉。
改用ViewPager2内部RecyclerView的addOnItemTouchListener,
这是RecyclerView专门提供的触摸观察接口,在RecyclerView
处理事件之前通知listener,保证能看到所有触摸事件。

使用rawY避免坐标系问题,阈值60px(约45dp@120dpi)。

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
dongliang
2026-04-28 21:09:48 +09:30
parent 6021171a40
commit 68f3b2d890

View File

@@ -2,10 +2,12 @@ package com.xiaoqu.watch.ui.home
import android.os.Bundle
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import android.widget.Toast
import androidx.recyclerview.widget.RecyclerView
import androidx.core.os.bundleOf
import androidx.fragment.app.viewModels
import androidx.lifecycle.Lifecycle
@@ -145,10 +147,9 @@ class HomeFragment : BaseFragment<FragmentHomeBinding>() {
showRevokeConfirm()
}
// 面板关闭时恢复 ViewPager2 滑动和下拉检测
// 面板关闭时恢复 ViewPager2 滑动
punchPanel.onDismiss = {
binding.viewPager.isUserInputEnabled = true
binding.swipeDownLayout.swipeEnabled = true
}
}
@@ -204,9 +205,8 @@ class HomeFragment : BaseFragment<FragmentHomeBinding>() {
/** 展开打卡面板 */
private fun showPunchPanel() {
if (punchPanel.isShowing) return
// 禁用 ViewPager2 滑动和下拉检测
// 禁用 ViewPager2 滑动
binding.viewPager.isUserInputEnabled = false
binding.swipeDownLayout.swipeEnabled = false
// 查询考勤状态
punchViewModel.fetchAttendance()
// 展开面板
@@ -215,17 +215,51 @@ class HomeFragment : BaseFragment<FragmentHomeBinding>() {
// ===== 下拉手势 =====
/** 触摸起始 Y */
private var touchStartY = 0f
/** 触摸起始 X */
private var touchStartX = 0f
/** 本次手势是否已触发过下拉 */
private var swipeTriggered = false
/**
* 初始化下拉手势检测
* 使用 SwipeDownLayout 在 onInterceptTouchEvent 中检测下拉
* 比 setOnTouchListener 更可靠——能在事件被子 View 消费前看到
* 通过 RecyclerView.OnItemTouchListener 监听 ViewPager2 内部触摸
* 这是最可靠的方式——RecyclerView 在处理事件前会先通知所有 listener
*/
private fun initSwipeDownDetector() {
binding.swipeDownLayout.onSwipeDown = {
// 只在主页page=1且面板未展开时响应
if (binding.viewPager.currentItem == 1 && !punchPanel.isShowing) {
showPunchPanel()
}
// ViewPager2 内部 RecyclerView 需等布局完成后获取
binding.viewPager.post {
val recyclerView = binding.viewPager.getChildAt(0) as? RecyclerView
recyclerView?.addOnItemTouchListener(object : RecyclerView.SimpleOnItemTouchListener() {
override fun onInterceptTouchEvent(rv: RecyclerView, e: MotionEvent): Boolean {
when (e.action) {
MotionEvent.ACTION_DOWN -> {
touchStartY = e.rawY
touchStartX = e.rawX
swipeTriggered = false
}
MotionEvent.ACTION_MOVE -> {
if (swipeTriggered) return false
// 只在主页page=1且面板未展开时响应
if (binding.viewPager.currentItem != 1) return false
if (punchPanel.isShowing) return false
val dy = e.rawY - touchStartY
val dx = e.rawX - touchStartX
// 下滑超过 60px 且方向以垂直为主
if (dy > 60 && Math.abs(dy) > Math.abs(dx) * 1.5f) {
swipeTriggered = true
showPunchPanel()
}
}
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
swipeTriggered = false
}
}
return false // 不拦截ViewPager2 正常工作
}
})
}
}