Search code examples
iosobjective-cuipangesturerecognizercgaffinetransform

CGAffineTransform an UIView with UIPanGestureRecognizer


I have view A, add sub on self view. And i want when i draw panGestureRegonizer on view A, view A will move follow draw.

And while moving view A will scale. View A will scale to smaller when view move to top/left/bottom/right of sreen and scale to larger when view move to center of screen.

I have try many solution, but i can not make it.

Please suggest help me?


Solution

  • Logic: You have coordinate system(CS) with center, x and y. When the user uses pan gesture, he/she generates sequence of points in the CS. So our task is to measure the distance between the center of the CS and users' points. When we have the furthest distance, we can calculate scale factor for our scaling view.

    var center: CGPoint! //center of the CS
    let maxSize: CGSize = CGSize.init(width: 100, height: 100) // maximum size of our scaling view
    var maxLengthToCenter: CGFloat! //maximum distance from the center of the CS to the furthest point in the CS
    
    private func prepareForScaling() {
        self.center = self.view.center //we set the center of our CS to equal the center of the VC's view
        let frame = self.view.frame
        //the furthest distance in the CS is the diagonal, and we calculate it using pythagoras theorem
        self.maxLengthToCenter = (frame.width*frame.width + frame.height*frame.height).squareRoot() 
    }
    

    Then we need to call our setup functional to have our data ready for scaling functionality - we can do this in viewDidLoad:

    override func viewDidLoad() {
        super.viewDidLoad()  
        self.prepareForScaling()
    }
    

    Then we need a helper function to calculates the scaled size of our view, for user's pan gesture current position on the screen.

    private func scaledSize(for location: CGPoint) -> CGSize {
        //calculate location x,y differences from the center
        let xDifference = location.x - self.center.x
        let yDifference = location.y - self.center.y
    
        //calculate the scale factor - note that this factor will be between 0.0(center) and 0.5(diagonal - furthest point)    
        //It is due our measurement - from center to view's edge. Consider multiplying this factor with your custom constant.
        let scaleFactor = (xDifference*xDifference + yDifference*yDifference).squareRoot()/maxLengthToCenter
        //create scaled size with maxSize and current scale factor
        let scaledSize = CGSize.init(width: maxSize.width*(1-scaleFactor), height: maxSize.height*(1-scaleFactor))
    
        return scaledSize
    }
    

    And finally, we need to modify our pan gesture action to change the size of A:

    @IBAction func panGestureAction(_ sender: UIPanGestureRecognizer) {
        UIView.animateKeyframes(withDuration: 0.1, delay: 0, options: UIViewKeyframeAnimationOptions.calculationModeLinear, animations: {
    
            let location = sender.location(in: sender.view?.superview)
    
            sender.view?.frame = CGRect.init(origin: CGPoint.init(x: 0, y: 0), size: self.scaledSize(for: location))
    
            sender.view?.center = location
        })
    }