In apple's documentation, I did not find any gesture related to shake for swiftUI. So how to detect it?
I am very new to swift programming and this question really bothers me for a long time.
In UIKit If I want to detect shake gesture is quite simple and straight forward. In swiftUI, there are bunch of gestures like tap drag rotation, however I cannot find shake gesture in official documentation or anyone who asked. Is this possible in swiftUI to achieve the same result? Or they just forget to add it into the swiftUI framework...
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?
I made this work using a view controller inside of a UIViewControllerRepresentable
view.
Corresponding UIViewControllerRepresentable
and 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")
}
}
How to implement it:
struct ContentView: View {
var body: some View {
ZStack {
ShakableViewRepresentable()
.allowsHitTesting(false)
/* Other views, in VStack or whatever it may be */
}
}
}
You can add a new notification and override UIWindow.motionEnded
in an extension (as also mentioned in an earlier answer):
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)
}
}
With this in place, it's easy to subscribe to the notification in your view:
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."
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With