Improved Magnify Gesture
We can smooth out the Magnify Gesture by multiplying the magnification by the initial scale of the entity.
I left this note at the end of the post on Magnify Gesture.
Issue: This doesn’t take into account the initial scale of the entity. If the entity starts at a scale of anything other than 1, you will see it “snap” to the starting scale of the gesture.
We can fix this in the same way we fixed Drag Gesture in Improved Drag Gesture. We just need to:
- Capture the initial scale of the entity when the gesture starts
- Multiply the magnification by the initial scale of each axis
- Apply the new scale
- Clean up the state when the gesture ends
struct Example011: View {
var body: some View {
RealityView { content in
// Load the scene from the Reality Kit bundle
if let scene = try? await Entity(named: "GestureLabs", in: realityKitContentBundle) {
content.add(scene)
// Lower the entire scene to the bottom of the volume
scene.position.y = -0.4
}
}
.modifier(MagnifyGestureImproved())
}
}
struct MagnifyGestureImproved: ViewModifier {
@State var isScaling: Bool = false
@State var initialScale: SIMD3<Float> = .init(repeating: 1.0)
func body(content: Content) -> some View {
content
.gesture(
MagnifyGesture()
.targetedToAnyEntity()
.onChanged { value in
// Cache the entity's initial scale when the gesture starts
if !isScaling {
isScaling = true
initialScale = value.entity.scale
}
// Get the magnification from the gesture
let magnification = Float(value.magnification)
let minScale: Float = 0.25
let maxScale: Float = 3
// Multiply the magnification by the initial scale to get the new scale
// Clamp scale values for each axis independently
let newScaleX = min(max(initialScale.x * magnification, minScale), maxScale)
let newScaleY = min(max(initialScale.y * magnification, minScale), maxScale)
let newScaleZ = min(max(initialScale.z * magnification, minScale), maxScale)
// Apply the clamped scale to the entity
value.entity.setScale(
.init(x: newScaleX, y: newScaleY, z: newScaleZ),
relativeTo: value.entity.parent!
)
}
.onEnded { value in
// Clean up when the gesture has ended
isScaling = false
initialScale = .init(repeating: 1.0)
}
)
}
}Video Demo
Support our work so we can continue to bring you new examples and articles.

Follow Step Into Vision