【问题标题】:How to track all touches across SwiftUI app如何跨 SwiftUI 应用程序跟踪所有触摸
【发布时间】:2020-09-16 20:25:50
【问题描述】:

我正在尝试在 SwiftUI 应用中实现锁屏。

我需要跟踪每个事件以重新启动锁定计时器。

在 UIKit 应用程序中,我使用了这种方法 - 覆盖 UIApplication,它允许了解整个应用程序中的任何事件:

override func sendEvent(_ event: UIEvent) {
  super.sendEvent(event)

  switch event.type {
  case .touches:
    // Post Notification or Delegate here
  default:
    break
  }
}

但在 SwiftUI 中不再支持它。 我尝试添加

.onTapGesture {}

到根 ContentView,但它没有按预期工作。

有什么办法可以避免添加

.onTapGesture {}

应用中的每一个视图?

【问题讨论】:

  • 你可以看到这个答案:stackoverflow.com/a/60010955/8697793 - 你可以调用你的自定义函数而不是 endEditing。
  • 是的,这是一个很好的答案,但是没有 Scenedelegate 和 Window 的 iOS 14 存在一些问题

标签: ios swift swiftui ios14


【解决方案1】:

这是一个可能的解决方案:

@main
struct TestApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
                .onAppear(perform: UIApplication.shared.addTapGestureRecognizer)
        }
    }
}

extension UIApplication {
    func addTapGestureRecognizer() {
        guard let window = windows.first else { return }
        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(tapAction))
        tapGesture.requiresExclusiveTouchType = false
        tapGesture.cancelsTouchesInView = false
        tapGesture.delegate = self
        window.addGestureRecognizer(tapGesture)
    }

    @objc func tapAction(_ sender: UITapGestureRecognizer) {
        print("tapped")
    }
}

extension UIApplication: UIGestureRecognizerDelegate {
    public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        return true // set to `false` if you don't want to detect tap during other gestures
    }
}

【讨论】:

  • 我在使用此代码时出现此错误'windows' was deprecated in iOS 15.0: Use UIWindowScene.windows on a relevant window scene instead
  • @RolandLariotte 应该是警告而不是错误。你可以用这个得到windows.first 的等价物。 connectedScenes.compactMap { $0 as? UIWindowScene }.flatMap { $0.windows }.first { $0.isKeyWindow } 您将在 SO 上看到的其他答案将包括对 .activationState == foregroundActive 的检查,但对于此特定实现,您应该将其关闭。
【解决方案2】:

基于pawello2222's solution,我添加了 UIPanGestureRecognizer 以便在滚动或滑动应用时也能够识别。还添加了一个通知观察者,以便在从键盘输入文本时进行识别。解决方案如下所示:

@main
struct YourApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
                .onAppear {
                    // Interaction recognizer implementation
                    UIApplication.shared.addInteractionRecognizer()
                }
        }
    }
}

extension UIApplication {
    func addInteractionRecognizer() {
        // Notification observer to track text changes from keyboard
        NotificationCenter.default.addObserver(self, selector: #selector(didInteractWithApp), name: UITextField.textDidChangeNotification, object: nil)
        
        guard let window = windows.first else { return }
        
        // Gestures recognizers to track
        let gestureRecognizers = [
            UITapGestureRecognizer(target: self, action: #selector(didInteractWithApp)),
            UIPanGestureRecognizer(target: self, action: #selector(didInteractWithApp))
        ]
        
        gestureRecognizers.forEach {
            $0.requiresExclusiveTouchType = false
            $0.cancelsTouchesInView = false
            $0.delegate = self
            window.addGestureRecognizer($0)
        }
    }
    
    @objc func didInteractWithKeyboard() {
        // Restart the lock timer
    }
    
    @objc func didInteractWithApp(_ sender: UIGestureRecognizer) {
        // Optional: Validate UIPanGestureRecognizer has ended, cancelled or failed, to prevent overloading for restarting timer. Remove if not needed
        let allowedStates: [UIGestureRecognizer.State] = [.ended, .cancelled, .failed]
        if sender as? UIPanGestureRecognizer != nil, !allowedStates.contains(sender.state) {
            return
        }
        
        // Restart the lock timer
    }
}

extension UIApplication: UIGestureRecognizerDelegate {
    public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        // Set to true to recognize gestures specified above while allowing user interact with other gestures in the app and not to block them with them
        return true
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-12
    • 1970-01-01
    相关资源
    最近更新 更多