![](/img/trans.png)
[英]Setting EnvironmentObject from a Shake Gesture (using UIKit) in SwiftUI doesn't update View
[英]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 完成了这项工作。
对应的UIViewControllerRepresentable
和UIViewController
:
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.