Creating a Tilt Effect in SwiftUI

Natko Biscan
3 min readAug 22, 2023

Have you ever seen apps react as you tilt your device? This effect is found in various applications, such as iOS’ Measure app. That’s a clever technique that breathes a bit of life into app interactions or is providing us with some useful data. Let’s dive right into crafting this dynamic element using SwiftUI and CoreMotion. 🤿

Phone Tilt Detection 🧭

To measure the device position, we’ll utilize the CoreMotion framework. Using the CMMotionManager class and its methods startDeviceMotionUpdates() and stopDeviceMotionUpdates(), we can retrieve lots of motion and position data from the device. Our focus will be on three key parameters:

- Roll: This represents the rotation around a longitudinal axis that passes from the device’s top to bottom.
- Pitch: Referring to the rotation around a lateral axis spanning from side to side.
- Yaw: This describes rotation around an axis extending vertically through the device, perpendicular to the body, with its origin at the center of gravity and directed toward the device’s bottom.

Setting the deviceMotionUpdateInterval in our case defines the animation’s smoothness. However, it’s important to note that this setting will also impact the device’s resource usage.


if motionManager.isDeviceMotionAvailable {
motionManager.deviceMotionUpdateInterval = 0.01
motionManager.startDeviceMotionUpdates(to: .main) { motion, _ in
if let motion {
let roll = motion.attitude.roll
let pitch = motion.attitude.pitch
let yaw = motion.attitude.yaw
}
}
}

From this point, we can obtain additional information, such as determining the compass direction using the obtained yaw value. Feel free to experiment with this functionality.

Utilizing the Effect 🪄

To create the desired visual effect, we’ll use the roll and pitch values acquired earlier. Since these values are in radians, let’s convert them to degrees:

extension Double {
func toDegrees() -> Double {
self * 180.0 / .pi
}
}

We’ll then leverage the inverted roll and pitch values to achieve the desired tilt effect:

yRotation = -roll
xRotation = -pitch

Next, we’ll employ SwiftUI’s rotation3DEffect() to manipulate a rectangle. Keep in mind that it is also possible to avoid conversion and just use the radians.

RoundedRectangle(cornerRadius: 20, style: .circular)
.frame(width: 200, height: 100)
.rotation3DEffect(.degrees(xRotation), axis: (x: -1, y: 0, z: 0))
.rotation3DEffect(.degrees(yRotation), axis: (x: 0, y: 1, z: 0))

And that’s the core of it. Here’s the effect applied on a view element:

The effect offers great diversity and this is just a very basic example. For instance, you can replace phone orientation with a gesture like DragGesture to craft a different UI experience.

Hope you found this information helpful. Here’s to the next project! 🥂

--

--