Spatial SwiftUI: transform3DEffect
Exploring some uses of transform3DEffect and AffineTransform3D.
We recently took a look at both the offset and rotation3DEffect modifiers. We can use transform3DEffect to take complete control of the transform of our view.
This modifier takes an AffineTransform3D. There are many options for creating an AffineTransform3D. I’ll start with a few simple examples. Make sure to check the docs to find the best one for your use case.
Translate (move) the view using a Vector3D
.transform3DEffect(AffineTransform3D(translation: Vector3D(x: 25, y: 25, z: 50)))Rotate the view using Rotation3D
.transform3DEffect(AffineTransform3D(rotation: Rotation3D(angle: Angle2D(degrees: 20), axis: .x)))Scale the view using Size3D
.transform3DEffect(AffineTransform3D(scale: Size3D(vector: [0.5, 0.5, 0.5])))Combine these together
.transform3DEffect(AffineTransform3D(
scale: Size3D(vector: [0.5, 0.5, 0.5]),
rotation: Rotation3D(angle: Angle2D(degrees: 20), axis: .x),
translation: Vector3D(x: 25, y: 25, z: 50)
))These are the signatures that I use most often, but there are many others.
Watch the video demo:
Full example code:
struct Example033: View {
@State fileprivate var transformMode: TransformType = .none
var body: some View {
HStack() {
List {
Section("Transform Mode") {
ForEach(TransformType.allCases, id: \.self) { transformType in
Button(transformType.rawValue) {
self.transformMode = transformType
}
}
}
}
.frame(maxWidth: .infinity)
ZStack {
RoundedRectangle(cornerRadius: 12.0)
.foregroundStyle(.thickMaterial)
.frame(width: 200, height: 200)
RoundedRectangle(cornerRadius: 12.0)
.foregroundStyle(.stepRed)
.frame(width: 200, height: 200)
.modifier(ExploringTransform3DEffect(mode: $transformMode))
}
.frame(maxWidth: .infinity)
}
.padding(EdgeInsets(top: 24, leading: 12, bottom: 12, trailing: 12))
}
}
fileprivate enum TransformType: String, CaseIterable {
case none = "None"
case translate = "Translate"
case rotate = "Rotate"
case scale = "Scale"
case combine = "Scale+Rotate+Translate"
}
fileprivate struct ExploringTransform3DEffect: ViewModifier {
@Binding var mode: TransformType
func body(content: Content) -> some View {
switch mode {
case .none:
content
case .translate:
content
.transform3DEffect(AffineTransform3D(translation: Vector3D(x: 25, y: 25, z: 50)))
case .rotate:
content
.transform3DEffect(AffineTransform3D(rotation: Rotation3D(angle: Angle2D(degrees: 20), axis: .x)))
case .scale:
content
.transform3DEffect(AffineTransform3D(scale: Size3D(vector: [0.5, 0.5, 0.5])))
case .combine:
content
.transform3DEffect(AffineTransform3D(
scale: Size3D(vector: [0.5, 0.5, 0.5]),
rotation: Rotation3D(angle: Angle2D(degrees: 20), axis: .x),
translation: Vector3D(x: 25, y: 25, z: 50)
))
}
}
}Support our work so we can continue to bring you new examples and articles.
Download the Xcode project with this and many more examples from Step Into Vision.
Some examples are provided as standalone Xcode projects. You can find those here.

Follow Step Into Vision