iosswiftuiviewuikituipangesturerecognizer

Issue with scaling when UIView is rotated upside down


I'm trying to rotate and scale UIView which has UIImageView inside as subView with one finger using UIPanGestureRecognizer. both rotation and scaling works fine in regular situations but when view is rotated upside down then it works in opposite direction instead of scaling up it scales down and vice versa, also when rotated at corner points it kind of flickers, don't work properly. results are shown in these gifs :

issue

another issue

here is how i'm trying to achieve this :

   @objc func ScaleGest(gesture: UIPanGestureRecognizer) {
    guard let gestureSuperView = gesture.view?.superview else { return }

    let center = frameScaleBut.center
    let touchLocation = gesture.location(in: self.view)
    
    if gesture.state == UIPanGestureRecognizer.State.began {
        self.initialDistance = distance(center, touchLocation)
    } else if gesture.state == UIPanGestureRecognizer.State.changed {
        
        let dist = distance(center, touchLocation) - initialDistance
        
        let smallScale: CGFloat = editingMode == .sticker ? 90 : 190

        let nextScale: CGSize = CGSize(width: gestureSuperView.bounds.width + dist, height: gestureSuperView.bounds.height + dist)
        
        if (nextScale.width >= (self.view.frame.width * 0.8)) || nextScale.width <= smallScale {
            return
        }
        
        gestureSuperView.bounds.size = CGSize(width: gestureSuperView.bounds.width + dist, height: gestureSuperView.bounds.height + dist)
    }
   }

i get distance with this method from this answer https://stackoverflow.com/a/1906659/20306199

func distance(_ a: CGPoint, _ b: CGPoint) -> CGFloat {
    let xDist = a.x - b.x
    let yDist = a.y - b.y
    return CGFloat(sqrt(xDist * xDist + yDist * yDist))
}

this works fine when object has no rotation, but i think when object is rotated upside down it still works with same coordinates but in reality it should those values in opposite manner, can anyone please help me to understand or achieve this, thanks.


Solution

  • The problem is not in distance(_:_:) function, but in the center parameter. Your center parameter is determined in small images coordinate space, but gestureLocation is determined in view’s coordinate space. You can use convert(_:to:) method to do that. You can read about it here.

    UPD: Actually you don't need to calculate distance between frameScaleBut.center and gesture.location(in: self.view). Why? Because self.initialDistance almost always will be around 0. So let dist = distance(center, touchLocation) - initialDistance will always be positive. Instead calculate distance between gestureSuperView.center and gesture.location(in: self.view). gestureSuperView is already in view coordinate space.