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.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.TextView import android.widget.TextView
import android.widget.Toast import android.widget.Toast
import androidx.recyclerview.widget.RecyclerView
import androidx.core.os.bundleOf import androidx.core.os.bundleOf
import androidx.fragment.app.viewModels import androidx.fragment.app.viewModels
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
@@ -145,10 +147,9 @@ class HomeFragment : BaseFragment<FragmentHomeBinding>() {
showRevokeConfirm() showRevokeConfirm()
} }
// 面板关闭时恢复 ViewPager2 滑动和下拉检测 // 面板关闭时恢复 ViewPager2 滑动
punchPanel.onDismiss = { punchPanel.onDismiss = {
binding.viewPager.isUserInputEnabled = true binding.viewPager.isUserInputEnabled = true
binding.swipeDownLayout.swipeEnabled = true
} }
} }
@@ -204,9 +205,8 @@ class HomeFragment : BaseFragment<FragmentHomeBinding>() {
/** 展开打卡面板 */ /** 展开打卡面板 */
private fun showPunchPanel() { private fun showPunchPanel() {
if (punchPanel.isShowing) return if (punchPanel.isShowing) return
// 禁用 ViewPager2 滑动和下拉检测 // 禁用 ViewPager2 滑动
binding.viewPager.isUserInputEnabled = false binding.viewPager.isUserInputEnabled = false
binding.swipeDownLayout.swipeEnabled = false
// 查询考勤状态 // 查询考勤状态
punchViewModel.fetchAttendance() punchViewModel.fetchAttendance()
// 展开面板 // 展开面板
@@ -215,18 +215,52 @@ class HomeFragment : BaseFragment<FragmentHomeBinding>() {
// ===== 下拉手势 ===== // ===== 下拉手势 =====
/** 触摸起始 Y */
private var touchStartY = 0f
/** 触摸起始 X */
private var touchStartX = 0f
/** 本次手势是否已触发过下拉 */
private var swipeTriggered = false
/** /**
* 初始化下拉手势检测 * 初始化下拉手势检测
* 使用 SwipeDownLayout 在 onInterceptTouchEvent 中检测下拉 * 通过 RecyclerView.OnItemTouchListener 监听 ViewPager2 内部触摸
* 比 setOnTouchListener 更可靠——能在事件被子 View 消费前看到 * 这是最可靠的方式——RecyclerView 在处理事件前会先通知所有 listener
*/ */
private fun initSwipeDownDetector() { private fun initSwipeDownDetector() {
binding.swipeDownLayout.onSwipeDown = { // 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且面板未展开时响应 // 只在主页page=1且面板未展开时响应
if (binding.viewPager.currentItem == 1 && !punchPanel.isShowing) { 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() showPunchPanel()
} }
} }
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
swipeTriggered = false
}
}
return false // 不拦截ViewPager2 正常工作
}
})
}
} }
// ===== 主页 ===== // ===== 主页 =====