fix: 下拉手势改用Activity.dispatchTouchEvent检测

前两种方案(SwipeDownLayout.onInterceptTouchEvent、
RecyclerView.OnItemTouchListener)均无法检测到下拉。

改用Activity.dispatchTouchEvent——触摸事件链最顶层,
在任何View处理之前就能看到所有触摸事件,不可能被拦截。

HomeFragment注册回调,onDestroyView时清理避免泄漏。

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
dongliang
2026-04-28 21:13:46 +09:30
parent 68f3b2d890
commit b274012019
2 changed files with 51 additions and 43 deletions

View File

@@ -2,6 +2,7 @@ package com.xiaoqu.watch.app
import android.content.pm.ActivityInfo
import android.os.Bundle
import android.view.MotionEvent
import android.view.View
import androidx.activity.OnBackPressedCallback
import androidx.appcompat.app.AppCompatActivity
@@ -10,6 +11,7 @@ import com.xiaoqu.watch.service.manager.SystemStateMonitor
import dagger.hilt.android.AndroidEntryPoint
import timber.log.Timber
import javax.inject.Inject
import kotlin.math.abs
/**
* 主 ActivityLauncher 模式,单 Activity + 多 Fragment 架构)
@@ -54,6 +56,43 @@ class MainActivity : AppCompatActivity() {
systemStateMonitor.unregister()
}
// ===== 下拉手势检测Activity 级别,不可能被子 View 拦截) =====
/** 下拉回调(由 HomeFragment 注册) */
var onSwipeDown: (() -> Unit)? = null
private var touchStartY = 0f
private var touchStartX = 0f
private var swipeTriggered = false
override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
// 在事件分发给任何 View 之前,先检测下拉手势
if (onSwipeDown != null) {
when (ev.action) {
MotionEvent.ACTION_DOWN -> {
touchStartY = ev.rawY
touchStartX = ev.rawX
swipeTriggered = false
}
MotionEvent.ACTION_MOVE -> {
if (!swipeTriggered) {
val dy = ev.rawY - touchStartY
val dx = ev.rawX - touchStartX
// 下滑超过 50px 且垂直方向为主
if (dy > 50 && abs(dy) > abs(dx) * 1.5f) {
swipeTriggered = true
onSwipeDown?.invoke()
}
}
}
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
swipeTriggered = false
}
}
}
return super.dispatchTouchEvent(ev)
}
/**
* 物理返回键拦截:
* - 已绑定用户 → 开启 NFC 打卡模式(后续模块实现)

View File

@@ -2,12 +2,10 @@ 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
@@ -124,6 +122,12 @@ class HomeFragment : BaseFragment<FragmentHomeBinding>() {
observePunchState()
}
override fun onDestroyView() {
super.onDestroyView()
// 清理 Activity 下拉回调,避免泄漏
(activity as? com.xiaoqu.watch.app.MainActivity)?.onSwipeDown = null
}
// ===== 打卡面板 =====
/** 初始化打卡面板 */
@@ -215,52 +219,17 @@ class HomeFragment : BaseFragment<FragmentHomeBinding>() {
// ===== 下拉手势 =====
/** 触摸起始 Y */
private var touchStartY = 0f
/** 触摸起始 X */
private var touchStartX = 0f
/** 本次手势是否已触发过下拉 */
private var swipeTriggered = false
/**
* 初始化下拉手势检测
* 通过 RecyclerView.OnItemTouchListener 监听 ViewPager2 内部触摸
* 这是最可靠的方式——RecyclerView 在处理事件前会先通知所有 listener
* 在 Activity.dispatchTouchEvent 中检测——触摸事件链最顶层,不会被任何子 View 拦截
*/
private fun initSwipeDownDetector() {
// 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
(activity as? com.xiaoqu.watch.app.MainActivity)?.onSwipeDown = {
// 只在主页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
if (binding.viewPager.currentItem == 1 && !punchPanel.isShowing) {
showPunchPanel()
}
}
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
swipeTriggered = false
}
}
return false // 不拦截ViewPager2 正常工作
}
})
}
}
// ===== 主页 =====