Introduction
In this tutorial, we will learn how to zoom, drag, and rotate an image simultaneously in SwiftUI. We will create a custom SwiftUI view that allows users to interact with an image by zooming, dragging, and rotating it. This functionality is commonly used in photo editing apps and can enhance the user experience of your app.
Prerequisites
- Xcode 16.0 or later: Ensure you have the latest version of Xcode installed on your device.
Zooming an Image in SwiftUI
To enable zooming on an image in SwiftUI, we can use the MagnificationGesture
modifier. This modifier allows users to pinch to zoom in and out of an image. Here’s how you can implement zooming on an image:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
import SwiftUI
struct ZoomingImageView: View {
@State private var scale: CGFloat = 1.0
@State private var lastScale = 0.0
var body: some View {
Image("example-image")
.resizable()
.scaleEffect(scale)
.scaledToFit()
.gesture(scaleGesture)
}
var scaleGesture: some Gesture {
MagnificationGesture(minimumScaleDelta: 0)
.onChanged { value in
withAnimation(.interactiveSpring()) {
scale = handleScaleChange(value)
}
}
.onEnded { _ in
lastScale = scale
}
}
private func handleScaleChange(_ zoom: CGFloat) -> CGFloat {
lastScale + zoom - (lastScale == 0 ? 0 : 1)
}
}
|
In the code snippet above, we define a ZoomingImageView
struct that contains an Image
view. We use the scaleEffect
modifier to apply the zooming effect based on the scale
state variable. The MagnificationGesture
is added to the image to handle the pinch gesture for zooming. The onChanged
closure updates the scale
value based on the pinch gesture’s scale factor. The onEnded
closure stores the last scale value for future reference.
Dragging an Image in SwiftUI
To enable dragging on an image in SwiftUI, we can use the DragGesture
modifier. This modifier allows users to drag an image across the screen. Here’s how you can implement dragging on an image:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
import SwiftUI
struct DraggingImageView: View {
@State private var offset = CGSize.zero
@State private var lastOffset = CGSize.zero
var body: some View {
Image("example-image")
.resizable()
.offset(offset)
.scaledToFit()
.gesture(dragGesture)
}
var dragGesture: some Gesture {
DragGesture(minimumDistance: 0)
.onChanged { value in
withAnimation(.interactiveSpring()) {
offset = handleOffsetChange(value.translation)
}
}
.onEnded { _ in
lastOffset = offset
}
}
private func handleOffsetChange(_ offset: CGSize) -> CGSize {
var newOffset: CGSize = .zero
newOffset.width = offset.width + lastOffset.width
newOffset.height = offset.height + lastOffset.height
return newOffset
}
}
|
In the code snippet above, we define a DraggingImageView
struct that contains an Image
view. We use the offset
modifier to apply the dragging effect based on the offset
state variable. The DragGesture
is added to the image to handle the drag gesture. The onChanged
closure updates the offset
value based on the drag gesture’s translation. The onEnded
closure stores the last offset value for future reference.
Rotating an Image in SwiftUI
To enable rotating an image in SwiftUI, we can use the RotationGesture
modifier. This modifier allows users to rotate an image by using two fingers. Here’s how you can implement rotating an image:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
import SwiftUI
struct RotatingImageView: View {
@State private var rotation: Angle = .degrees(0)
@State private var lastRotation = Angle(degrees: 0)
var body: some View {
Image("example-image")
.resizable()
.rotationEffect(rotation)
.scaledToFit()
.gesture(rotationGesture)
}
var rotationGesture: some Gesture {
RotationGesture()
.onChanged { value in
withAnimation(.interactiveSpring()) {
rotation = handleRotationChange(value)
}
}
.onEnded { _ in
lastRotation = rotation
}
}
private func handleRotationChange(_ angle: Angle) -> Angle {
lastRotation + angle
}
}
|
In the code snippet above, we define a RotatingImageView
struct that contains an Image
view. We use the rotationEffect
modifier to apply the rotation effect based on the rotation
state variable. The RotationGesture
is added to the image to handle the rotation gesture. The onChanged
closure updates the rotation
value based on the rotation gesture’s angle. The onEnded
closure stores the last rotation value for future reference.
Combining Zooming, Dragging, and Rotating Simultaneously
To combine zooming, dragging, and rotating an image simultaneously in SwiftUI, we can use the simultaneousGesture
modifier. This modifier allows us to combine multiple gestures on a single view. Here’s how you can implement zooming, dragging, and rotating an image simultaneously:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
|
import SwiftUI
struct ZoomingDraggingRotatingImageView: View {
@State private var scale: CGFloat = 1.0
@State private var lastScale = 0.0
@State private var offset = CGSize.zero
@State private var lastOffset = CGSize.zero
@State private var rotation: Angle = .degrees(0)
@State private var lastRotation = Angle(degrees: 0)
var body: some View {
Image("example-image")
.resizable()
.scaleEffect(scale)
.rotationEffect(rotation)
.offset(offset)
.scaledToFit()
.gesture(
scaleGesture
.simultaneously(with: dragGesture)
.simultaneously(with: rotationGesture)
)
}
}
// MARK: - Scale
private extension ZoomingDraggingRotatingImageView {
var scaleGesture: some Gesture {
MagnificationGesture(minimumScaleDelta: 0)
.onChanged { value in
withAnimation(.interactiveSpring()) {
scale = handleScaleChange(value)
}
}
.onEnded { _ in
lastScale = scale
}
}
private func handleScaleChange(_ zoom: CGFloat) -> CGFloat {
lastScale + zoom - (lastScale == 0 ? 0 : 1)
}
}
// MARK: - Drag
private extension ZoomingDraggingRotatingImageView {
var dragGesture: some Gesture {
DragGesture(minimumDistance: 0)
.onChanged { value in
withAnimation(.interactiveSpring()) {
offset = handleOffsetChange(value.translation)
}
}
.onEnded { _ in
lastOffset = offset
}
}
private func handleOffsetChange(_ offset: CGSize) -> CGSize {
var newOffset: CGSize = .zero
newOffset.width = offset.width + lastOffset.width
newOffset.height = offset.height + lastOffset.height
return newOffset
}
}
// MARK: - Rotation
private extension ZoomingDraggingRotatingImageView {
var rotationGesture: some Gesture {
RotationGesture()
.onChanged { value in
withAnimation(.interactiveSpring()) {
rotation = handleRotationChange(value)
}
}
.onEnded { _ in
lastRotation = rotation
}
}
private func handleRotationChange(_ angle: Angle) -> Angle {
lastRotation + angle
}
}
|
Conclusion
In this tutorial, we learned how to zoom, drag, and rotate an image simultaneously in SwiftUI. By combining the MagnificationGesture
, DragGesture
, and RotationGesture
modifiers, we were able to create a custom SwiftUI view that allows users to interact with an image in a photo editing app. You can further customize the gestures and animations to suit your app’s design and user experience requirements. I hope you found this tutorial helpful, and feel free to leave any questions or feedback in the comments below. Happy coding!
References