I’m making an attempt to permit non-uniform scaling (horizontal or vertical) of a UIView rectangle that’s positioned over a Mapbox mapView and has already been rotated. Uniform scaling works properly, however once I try to use non-uniform scaling (scaling solely X or Y) utilizing transforms after rotation, the rectangle turns into distorted like a parallelogram.
To keep away from distortion, I as an alternative redraw the rectangle utilizing coordinate math on the finish of the gesture, however this makes the scaling really feel abrupt and never clean. I need to obtain clean, stay non-uniform scaling after rotation with out visible distortion. I’ve tried utilizing rework.scaledBy(x:y:), however it doesn’t preserve the rectangle’s orthogonality post-rotation.
How can I obtain clean, interactive, non-uniform scaling on a rotated view with out it deforming?
Code Snippets
Right here’s the pinchProcess
gesture handler:
@objc func handlePinchGesture(_ recognizer: UIPinchGestureRecognizer) {
guard isScalingEnabled, let targetView = self.scalingView else { return }
if recognizer.state == .started {
previousScale = 1.0
initialPinchLocation = recognizer.location(in: targetView)
}
if recognizer.state == .ended || recognizer.state == .cancelled {
if hasRotationApplied {
gestureDelegate?.applyScalingAndRedraw(for: targetView, axis: lastScaleAxis, scaleFactor: finalScaleValue)
} else {
gestureDelegate?.finalizeSnap(for: targetView, usingPoints: originalPoints)
}
return
}
if recognizer.numberOfTouches < 2 {
initialPinchLocation = recognizer.location(in: targetView)
return
}
let touchPointA = recognizer.location(ofTouch: 0, in: targetView)
let touchPointB = recognizer.location(ofTouch: 1, in: targetView)
lastScaleAxis = detectScaleAxis(from: touchPointA, to: touchPointB, basedOn: originalPoints)
let scaleFactor = recognizer.scale / previousScale
let xDiff = originalPoints[1].x - originalPoints[0].x
let yDiff = originalPoints[1].y - originalPoints[0].y
if xDiff == 0 || yDiff == 0 {
hasRotationApplied = false
change detectGestureDirection(touchPointA, point2: touchPointB) {
case "V":
targetView.rework = targetView.rework.scaledBy(x: 1, y: scaleFactor)
case "H":
targetView.rework = targetView.rework.scaledBy(x: scaleFactor, y: 1)
default:
targetView.rework = targetView.rework.scaledBy(x: scaleFactor, y: scaleFactor)
}
previousScale = recognizer.scale
} else {
finalScaleValue = recognizer.scale
hasRotationApplied = true
targetView.rework = targetView.rework.scaledBy(x: scaleFactor, y: scaleFactor)
}
previousScale = recognizer.scale
}
func applyScalingAndRedraw(for view: UIView, axis: String, scaleFactor: CGFloat) {
// Computes new factors primarily based on the scaling axis and applies redraw logic
// Geometry strategies replace coordinates and redraw the rectangle accurately
}