If you’ve ever used Instagram, you’ve likely encountered the pinch-to-zoom effect used to enlarge images. This effect allows users to zoom in on details and get a closer look at photos.
In this post, let’s have a look on how to create a similar zoom effect in SwiftUI.
Before getting started, if you need to check out the Instagram’s feature we are trying to replicate, you can check out a sample video below:
Creating a new SwiftUI project and adding an image asset:
You should be already familiar with the process of creating a new SwiftUI project and importing image assets if you are learning about gestures in SwiftUI.
A quick guide to creating a new SwiftUI project is given below.
- Open Xcode and create a new SwiftUI project.
- Select
App
as the project template under iOS section and click onNext
. - Give your project a name and click on
Next
. Make sure to selectSwiftUI
as the user interface. - Save the project in a location of your choice and click on
Create
.
Creating a new SwiftUI project
- For an image as a placeholder, import any image of your choice by dragging and dropping the image file into the assets folder of your project in the project navigator of Xcode.
In my project, I have used an image of a car as a placeholder
(Credits: Erik Mclean on Unsplash).
Add a new Image
view to the ContentView
struct
Inside the ContentView
struct present in the template, create a new Image
view.
Set the image to be resizable and scaled to fit the available space.
struct ContentView: View {
var body: some View {
Image("car")
.resizable()
.scaledToFit()
}
}
Add a scaleEffect
modifier to theImage view
Apply a scaleEffect
modifier to the Image
view, which will be used to adjust the scale of the image based on the user’s pinch gesture. Also, create a new private variable scale
of type CGFloat
and set it to 1.0
so as to set the initial scale of the image to 1.0
and track the scale of the image as the user performs the pinch gesture and store the changes in here.
struct ContentView: View {
@State private var scale: CGFloat = 1.0
var body: some View {
Image("car")
.resizable()
.scaledToFit()
.scaleEffect(scale)
}
}
Adding a MagnificationGesture
to the Image
view
Attach a MagnificationGesture
to the Image
view using the gesture
modifier. When the user changes the magnification value, update the scale
property using the onChanged
closure.
struct ContentView: View {
@State private var scale: CGFloat = 1.0
var body: some View {
Image("car")
.resizable()
.scaledToFit()
.scaleEffect(scale)
.gesture(MagnificationGesture()
.onChanged { value in
self.scale = value.magnitude
}
)
}
}
Add an onEnded
closure to the MagnificationGesture
Add an onEnded
closure to the MagnificationGesture
that sets the scale
property back to its original value of 1.0
when the user releases the pinch gesture. This will cause the image view to return to its original size and position.
struct ContentView: View {
@State private var scale: CGFloat = 1.0
var body: some View {
Image("car")
.resizable()
.scaledToFit()
.scaleEffect(scale)
.gesture(MagnificationGesture()
.onChanged { value in
self.scale = value.magnitude
}
.onEnded { _ in
self.scale = 1.0
}
)
}
}
Add a conditional statement to the onChanged
closure
Add a conditional statement to the onChanged
closure of the MagnificationGesture
that checks if the magnification value is less than 1.0
. If it is, set the scale
property to 1.0
, which will cause the image view to return to its original size. If the magnification value is greater than or equal to 1.0
, set the scale
property to the magnitude of the pinch gesture, as before.
This step is crucial because if the user performs a pinch gesture that is less than 1.0
, the image view will shrink to a size smaller than the original image. This is not the desired behavior, so we need to add a conditional statement to prevent this from happening.
struct ContentView: View {
@State private var scale: CGFloat = 1.0
var body: some View {
Image("car")
.resizable()
.scaledToFit()
.scaleEffect(scale)
.gesture(MagnificationGesture()
.onChanged { value in
if value.magnitude < 1.0 {
self.scale = 1.0
} else {
self.scale = value.magnitude
}
}
.onEnded { _ in
self.scale = 1.0
}
)
}
}
Some final touches:
Wrap the Image
in a VStack
and add a padding
modifier to the VStack
to add some space between the edges of the screen and the image view.
struct ContentView: View {
@State private var scale: CGFloat = 1.0
var body: some View {
VStack {
Image("car")
.resizable()
.scaledToFit()
.scaleEffect(scale)
.gesture(MagnificationGesture()
.onChanged { value in
if value.magnitude < 1.0 {
self.scale = 1.0
} else {
self.scale = value.magnitude
}
}
.onEnded { _ in
self.scale = 1.0
}
)
}
.padding()
}
}
Final result
Conclusion
Great, you’ve just created an Instagram-like zoom effect in SwiftUI. We’ve learnt about creating this using the MagnificationGesture
and scaleEffect
modifiers.
With just a few lines of code, you have added interactivity and a touch of elegance to your SwiftUI app.
Try experimenting with different images and gestures to create your own unique effects.
I hope you found this tutorial helpful.
Thank you for reading this far.