We have made it possible to scale, rotate, and move images using SwiftUI. The movement gesture is implemented independently, while the zoom and rotation gestures can be performed simultaneously using SimultaneousGesture.
When repeatedly performing image zoom gestures, at some point the image seemed to freeze, and any further zoom, rotation, or movement gestures were no longer possible.
I would like to know the code that will solve this problem and make it possible to permanently scale images.
import SwiftUI
struct ContentView: View {
@State private var offset: CGSize = .zero // drag value
@State private var lastOffset: CGSize = .zero // hold last drag value
@State private var scale: CGFloat = 1.0 // pinch scale value
@State private var lastScale: CGFloat = 1.0 // hold last scale value
@State private var angle: Angle = .zero // pinch angle value
@State private var lastAngle: Angle = .zero // hold last angle value
@State private var isReset: Bool = false
let minScale = 0.2 // minimum scale value
let maxScale = 5.0 // maximum scale value
var dragGesture: some Gesture { // Move
DragGesture()
.onChanged {
offset = CGSize(width: lastOffset.width + $0.translation.width, height: lastOffset.height + $0.translation.height)
}
.onEnded { _ in
lastOffset = offset
}
}
var scaleGesture: some Gesture { // Scaling
MagnificationGesture()
.onChanged {
if ($0 > minScale) && ($0 < maxScale) { // scaling range for pinch
scale = $0 * lastScale
}
}
.onEnded { _ in
lastScale = scale
}
}
var rotateGesture: some Gesture { // rotate
RotationGesture(minimumAngleDelta: .degrees(8)) // minimun start angle = 8degrees
.onChanged {
angle = $0 + lastAngle
}
.onEnded { _ in
lastAngle = angle
}
}
var body: some View {
NavigationStack {
VStack {
GeometryReader { geometry in
Image(systemName: "globe")
.resizable()
.scaledToFit()
.frame(maxWidth: .infinity, maxHeight: .infinity) // placement size
.rotationEffect(angle, anchor: .center) // rotationEffect must be first
.scaleEffect(scale) // scaleEffect must be after rotationEffect
.offset(offset) // offset is last
.gesture(dragGesture)
.gesture(SimultaneousGesture(rotateGesture, scaleGesture))
}
.toolbar {
ToolbarItem(placement: .topBarLeading) {
Spacer()
}
ToolbarItem(placement: .topBarTrailing) {
Button(action: {
isReset = true
}) {
Image(systemName: "arrow.trianglehead.clockwise")
.font(.title)
.foregroundColor(.red)
}
}
}
}
}
.onChange(of: isReset) {
if (isReset == true) {
offset = .zero; lastOffset = .zero
scale = 1.0; lastScale = 1.0
angle = .zero; lastAngle = .zero
}
isReset = false
}
}
}
We have made it possible to scale, rotate, and move images using SwiftUI. The movement gesture is implemented independently, while the zoom and rotation gestures can be performed simultaneously using SimultaneousGesture.
When repeatedly performing image zoom gestures, at some point the image seemed to freeze, and any further zoom, rotation, or movement gestures were no longer possible.
I would like to know the code that will solve this problem and make it possible to permanently scale images.
import SwiftUI
struct ContentView: View {
@State private var offset: CGSize = .zero // drag value
@State private var lastOffset: CGSize = .zero // hold last drag value
@State private var scale: CGFloat = 1.0 // pinch scale value
@State private var lastScale: CGFloat = 1.0 // hold last scale value
@State private var angle: Angle = .zero // pinch angle value
@State private var lastAngle: Angle = .zero // hold last angle value
@State private var isReset: Bool = false
let minScale = 0.2 // minimum scale value
let maxScale = 5.0 // maximum scale value
var dragGesture: some Gesture { // Move
DragGesture()
.onChanged {
offset = CGSize(width: lastOffset.width + $0.translation.width, height: lastOffset.height + $0.translation.height)
}
.onEnded { _ in
lastOffset = offset
}
}
var scaleGesture: some Gesture { // Scaling
MagnificationGesture()
.onChanged {
if ($0 > minScale) && ($0 < maxScale) { // scaling range for pinch
scale = $0 * lastScale
}
}
.onEnded { _ in
lastScale = scale
}
}
var rotateGesture: some Gesture { // rotate
RotationGesture(minimumAngleDelta: .degrees(8)) // minimun start angle = 8degrees
.onChanged {
angle = $0 + lastAngle
}
.onEnded { _ in
lastAngle = angle
}
}
var body: some View {
NavigationStack {
VStack {
GeometryReader { geometry in
Image(systemName: "globe")
.resizable()
.scaledToFit()
.frame(maxWidth: .infinity, maxHeight: .infinity) // placement size
.rotationEffect(angle, anchor: .center) // rotationEffect must be first
.scaleEffect(scale) // scaleEffect must be after rotationEffect
.offset(offset) // offset is last
.gesture(dragGesture)
.gesture(SimultaneousGesture(rotateGesture, scaleGesture))
}
.toolbar {
ToolbarItem(placement: .topBarLeading) {
Spacer()
}
ToolbarItem(placement: .topBarTrailing) {
Button(action: {
isReset = true
}) {
Image(systemName: "arrow.trianglehead.clockwise")
.font(.title)
.foregroundColor(.red)
}
}
}
}
}
.onChange(of: isReset) {
if (isReset == true) {
offset = .zero; lastOffset = .zero
scale = 1.0; lastScale = 1.0
angle = .zero; lastAngle = .zero
}
isReset = false
}
}
}
Share
Improve this question
asked Mar 27 at 13:50
BB-8BB-8
1075 bronze badges
3
- You will be able to instantly find a problem if you simply add some print statements inside the changed and on ended clauses. I can't really figure out all your code, but I'm guessing you almost certainly need to do something as well when the gesture begins as well as change and end, and don't fet cancel as well. As I say, if you just add print statements, you'll instantly find the problem. Writing touch related code is very subtle and tricky. – Fattie Commented Mar 27 at 17:51
- I checked the situation using the print statement, but couldn't determine the cause, so I submitted Feedback to Apple. FB17031685 – BB-8 Commented Mar 28 at 5:59
- Since MagnificationGesture is already deprecated, I checked using MagnifyGesture but I am getting the same issue. – BB-8 Commented Mar 28 at 6:00
1 Answer
Reset to default -1This issue does not occur if you define the image scaling gesture alone.
Problems arise when SimultaneousGesture allows multiple gestures to be performed simultaneously.
.gesture(scaleGesture) ---> No problems occur
.gesture(SimultaneousGesture(rotateGesture, scaleGesture)) ----> Problems occur
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744084342a4555886.html
评论列表(0条)