SwiftUI and Shake Gesture

Nicola De Filippo
2 min readDec 25, 2020

There isn’t a way to catch the shake gesture only using SwiftUI, so it’s necessary use these frameworks: Uikit and Combine .

Combine is very helpful in this case because how is wrote in the Apple documentation: “Combine declares publishers to expose values that can change over time, and subscribers to receive those values from the publishers.”

In the example, the goal is catch the Shake gesture with the UiKit, with the Combine framework we publish this event and get the combine published info in the SwiftUI view that is a subscriber. Let’s start.

We must create a Swift file, ShakeGestureManager.swift

import Foundation
import SwiftUI
import Combine
let messagePublisher = PassthroughSubject<Void, Never>()class ShakeViewController: UIViewController {override func motionBegan(_ motion: UIEvent.EventSubtype,
with event: UIEvent?) {
guard motion == .motionShake else { return }
messagePublisher.send()
}
}
struct ShakeViewRepresentable: UIViewControllerRepresentable {

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

}
}

Where the PassthroughSubject is a “A subject that broadcasts elements to downstream subscribers.” (from the Apple documentation). We need it to communicate with the SwiftUI View.

The ShakeViewController is a simple UIViewController that catches the shake Gesture. Like in the case of the Map, it’s not possible to use the UIViewController in the SwiftUI so we must create a struct that implement the UIViewControllerRepresentable that we can use in the SwiftUI View.

Now see the SwiftUI view:

import SwiftUIstruct ContentView: View {
@State var shaked = false

var body: some View {
NavigationView {
VStack{
ZStack {
ShakeViewRepresentable()
.allowsHitTesting(false)
VStack {
Text("Shake device to change view!")
}

}.onReceive(messagePublisher) { _ in
self.shaked = true
}
NavigationLink(destination: SecondView(), isActive: $shaked) {
EmptyView()
}
}
}
}
}

The state variable shaked it used to store the shaked event. In the navigationview there is a ZStack, where at the bottom (first element) there is the ShakeViewRepresentable that can’t get touch event from the user because allowsHitTesting is false, on the top there is a simple Text message. When the ZStack receives the messagePublisher, the shaked variable become true and the NavigationLink become active so the view navigates to the SecondView (that you can create how you want). Note the use of the EmptyView from the NavigationLink, it used to show nothing but to have a working link. That’s all. I hope that it can be helpful. You can get the code here.

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

Nicola De Filippo
Nicola De Filippo

Written by Nicola De Filippo

Software Engineer and Entrepreneur

No responses yet

Write a response