繁体   English   中英

如何检测 swiftUI 中的摇晃手势

[英]How to detect shake gesture in swiftUI

在苹果的文档中,我没有找到任何与 swiftUI 的抖动相关的手势。 那么如何检测呢?

我对 swift 编程非常陌生,这个问题确实困扰了我很长时间。

在 UIKit 中,如果我想检测摇晃手势非常简单直接。 在 swiftUI 中,有很多手势,例如点击拖动旋转,但是我在官方文档或任何询问的人中都找不到摇动手势。 这是否可能在 swiftUI 中达到相同的结果? 或者他们只是忘记将其添加到 swiftUI 框架中......

If it's not possible in swiftUI, then how am I going to import the motionEnded function in UIKit to the swiftUI view that I want to detect shake motion?

您可以在扩展中添加新通知并覆盖UIWindow.motionEnded (如之前的答案中所述):

extension NSNotification.Name {
    public static let deviceDidShakeNotification = NSNotification.Name("MyDeviceDidShakeNotification")
}

extension UIWindow {
    open override func motionEnded(_ motion: UIEvent.EventSubtype, with event: UIEvent?) {
        super.motionEnded(motion, with: event)
        NotificationCenter.default.post(name: .deviceDidShakeNotification, object: event)
    }
}

有了这个,很容易在你的视图中订阅通知:

struct Example: View {
    @State private var message = "Unshaken"

    var body: some View {
        Text(message)
            .onReceive(NotificationCenter.default.publisher(for: .deviceDidShakeNotification)) { _ in
                self.message = "Shaken, not stirred."
        }
    }
}

您可以从 ViewController 级别执行此操作。 例如:

final class MyVC: UIHostingController<ContentView> {

    override func motionBegan(_ motion: UIEvent.EventSubtype, with event: UIEvent?) {
        guard motion == .motionShake else { return }

        // Notify view.
    }
}

我正在尝试解决同样的问题。 对你来说任何成功。 我能够在 AppDelegate 中检测到抖动,但不知道如何使用我的 environmentObject 访问我的 SceneDelegate

我使用UIViewControllerRepresentable视图中的视图 controller 完成了这项工作。

对应的UIViewControllerRepresentableUIViewController

struct ShakableViewRepresentable: UIViewControllerRepresentable {

    func makeUIViewController(context: Context) -> ShakableViewController {
        ShakableViewController()
    }
    func updateUIViewController(_ uiViewController: ShakableViewController, context: Context) {}
}


class ShakableViewController: UIViewController {

    override func motionBegan(_ motion: UIEvent.EventSubtype, with event: UIEvent?) {
        guard motion == .motionShake else { return }

        /* Do something */
        print("Shaken")
    }
}

如何实现它:

struct ContentView: View {

    var body: some View {
        ZStack {
            ShakableViewRepresentable()
                .allowsHitTesting(false)

            /* Other views, in VStack or whatever it may be */
        }
    }
}

iOS 13, Swift 5... a solution that works with SwiftUI based in jk2K answer, with this obviously this is in the ContentView.swift file.

let messagePublisher = PassthroughSubject<String, Never>()

class ContentMode {

...

}

extension UIWindow {
 open override func motionEnded(_ motion: UIEvent.EventSubtype, with event:   UIEvent?) {
    if motion == .motionShake {
        print("Device shaken")
        messagePublisher.send("Stop Shaking Me")
    }
  }
}

您可以使用它在您的 UI 中选择它

.onReceive(messagePublisher) { (message) in
  // message = "Stop Shaking Me"
}

这是使用视图修饰符对上述内容进行的改进。

import SwiftUI
import Combine

private let motionShaked = PassthroughSubject<Void, Never>()

extension UIWindow {
     open override func motionEnded(_ motion: UIEvent.EventSubtype, with event: UIEvent?) {
        if motion == .motionShake {
            motionShaked.send()
        }
     }
}

private struct ShakeViewModifier: ViewModifier {
    let action: (() -> Void)

    init(perform action: @escaping (() -> Void)) {
        self.action = action
    }
        
    func body(content: Content) -> some View {
        content
            .onAppear {
            }
            .onReceive(motionShaked) {
                action()
            }
    }
}

extension View {
    public func onShake(perform action: @escaping (() -> Void)) -> some View {
        return self.modifier(ShakeViewModifier(perform: action))
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM