问题
I want to be able to resize and move an image in SwiftUI (like if it were a map) with pinch to zoom and drag it around.
With UIKit I embedded the image into a UIScrollView
and it took care of it, but I don't know how to do it in SwiftUI.
I tried using MagnificationGesture
but I cannot get it to work smoothly.
I've been searching about this for a while, does anyone know if there's an easier way?
回答1:
The SwiftUI API is pretty unhelpful here: the onChanged gives number relative to start of current zoom gesture and no obvious way within a callback to get the initial value. And there is an onEnded callback but easy to miss/forget.
A work around, add:
@State var lastScaleValue: CGFloat = 1.0
Then in the callback:
.gesture(MagnificationGesture().onChanged { val in
let delta = val / self.lastScaleValue
self.lastScaleValue = val
let newScale = self.scale * delta
//... anything else e.g. clamping the newScale
}.onEnded { val in
// without this the next gesture will be broken
self.lastScaleValue = 1.0
}
where newScale is your own tracking of scale (perhaps state or a binding). If you set your scale directly it will get messed up as on each tick the amount will be relative to previous amount.
回答2:
Looks like there isn't native support in SwiftUI's ScrollView, however, there's still a pretty simple way to do it.
Create a MagnificationGesture
like you were going for, but be sure to multiply your current scale by the value you get in the gesture's .onChanged
closure. This closure is giving you the change in zoom rather than the current scale value.
When you're zoomed out and begin to zoom in it won't increase from the current scale (0.5 to 0.6 as an arbitrary example), it will increase from 1 to 1.1. That's why you were seeing weird behavior.
This answer will work if the MagnificationGesture
is on the same view that has the .scaleEffect
. Otherwise, James' answer will work better.
struct ContentView: View {
@State var scale: CGFloat
var body: some View {
let gesture = MagnificationGesture(minimumScaleDelta: 0.1)
.onChanged { scaleDelta in
self.scale *= scaleDelta
}
return ScrollView {
// Your ScrollView content here :)
}
.gesture(gesture)
.scaleEffect(scale)
}
}
P.S. You may find that using a ScrollView
for this purpose is clunky and you aren't able to drag and zoom simultaneously. If this is the case & you aren't happy with it I would look into adding multiple gestures and adjusting your content's offset manually rather than using a ScrollView
.
来源:https://stackoverflow.com/questions/58341820/isnt-there-an-easy-way-to-pinch-to-zoom-in-an-image-in-swiftui