You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI中如何识别Siri Remote滑动手势及绕过未实现方案

嘿,这个问题我之前也折腾过!确实SwiftUI原生目前没有专门针对Siri Remote触摸板滑动的手势识别器,但咱们有几个靠谱的 workaround 能搞定:

解决方案1:封装UIKit的UIPanGestureRecognizer

UIKit对Apple TV的手势支持更成熟,咱们可以把UIPanGestureRecognizer包装成SwiftUI可用的View,精准识别触摸板滑动:

import SwiftUI
import UIKit

struct SiriRemotePanGestureView: UIViewRepresentable {
    var onPan: (CGPoint) -> Void
    
    func makeUIView(context: Context) -> UIView {
        let view = UIView()
        view.isUserInteractionEnabled = true
        let panGesture = UIPanGestureRecognizer(target: context.coordinator, action: #selector(Coordinator.handlePan(_:)))
        // 适配Apple TV触摸板的配置
        panGesture.minimumNumberOfTouches = 1
        panGesture.maximumNumberOfTouches = 1
        view.addGestureRecognizer(panGesture)
        return view
    }
    
    func updateUIView(_ uiView: UIView, context: Context) {}
    
    func makeCoordinator() -> Coordinator {
        Coordinator(onPan: onPan)
    }
    
    class Coordinator: NSObject {
        var onPan: (CGPoint) -> Void
        
        init(onPan: @escaping (CGPoint) -> Void) {
            self.onPan = onPan
        }
        
        @objc func handlePan(_ gesture: UIPanGestureRecognizer) {
            let translation = gesture.translation(in: gesture.view)
            onPan(translation)
            // 重置位移,确保每次滑动返回相对当前位置的偏移
            gesture.setTranslation(.zero, in: gesture.view)
        }
    }
}

// SwiftUI视图中使用示例
struct ContentView: View {
    @State private var offset = CGPoint.zero
    
    var body: some View {
        ZStack {
            SiriRemotePanGestureView { translation in
                self.offset.x += translation.x
                self.offset.y += translation.y
                print("滑动偏移:\(translation)")
            }
            .frame(maxWidth: .infinity, maxHeight: .infinity)
            
            Text("滑动我试试!")
                .offset(offset)
        }
    }
}

这个方法稳定性高,完美支持四个方向的滑动,和UIKit的手势逻辑完全一致。

解决方案2:使用SwiftUI的DragGesture(简易版)

如果需求不复杂,也可以直接用SwiftUI原生的DragGesture,调整参数适配触摸板的轻滑特性:

struct ContentView: View {
    @State private var offset = CGPoint.zero
    
    var body: some View {
        Text("滑动测试")
            .offset(offset)
            .gesture(
                DragGesture(minimumDistance: 1, coordinateSpace: .global)
                    .onChanged { value in
                        let translation = value.translation
                        self.offset.x += translation.x
                        self.offset.y += translation.y
                        print("DragGesture 滑动:\(translation)")
                    }
            )
            .frame(maxWidth: .infinity, maxHeight: .infinity)
    }
}

把minimumDistance设为1,是因为Siri Remote触摸板的滑动幅度通常很小。这个方法实现简单,但识别快速滑动时的精准度不如UIKit方案,适合简单场景。

解决方案3:监听UIKit触摸事件(进阶版)

如果需要最底层的触摸数据来自定义手势逻辑,可以通过Combine监听全局触摸事件:

import SwiftUI
import Combine

struct ContentView: View {
    @State private var cancellable: AnyCancellable?
    @State private var lastTouchLocation: CGPoint?
    
    var body: some View {
        Text("底层滑动监听")
            .frame(maxWidth: .infinity, maxHeight: .infinity)
            .onAppear {
                cancellable = NotificationCenter.default.publisher(for: UIApplication.touchesMovedNotification)
                    .sink { notification in
                        guard let touches = notification.userInfo?[UIApplication.touchesUserInfoKey] as? Set<UITouch>,
                              let touch = touches.first,
                              let window = touch.view?.window else { return }
                        
                        let currentLocation = touch.location(in: window)
                        if let lastLocation = lastTouchLocation {
                            let translation = CGPoint(x: currentLocation.x - lastLocation.x, y: currentLocation.y - lastLocation.y)
                            print("底层滑动偏移:\(translation)")
                            // 在这里处理自定义滑动逻辑
                        }
                        lastTouchLocation = currentLocation
                    }
            }
            .onDisappear {
                cancellable?.cancel()
            }
    }
}

这个方法能拿到最原始的触摸数据,但需要自己处理触摸的开始、移动和结束状态,代码相对复杂,适合需要高度自定义的场景。

内容的提问来源于stack exchange,提问作者Per Møller

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:53:37