swiftrotationuiimageviewuipangesturerecognizeruipinchgesturerecognizer

How to add a scaled, panned and rotated image from one view controller to another in exact same way as its scaled, panned and rotated, in Swift?


I have 2 view controllers,in which both have UIView added and UIImageView added programatically.In ViewControllerA-The image is scaled, panned and rotated. I want to show the same image with same scaled, panned and rotated value in ViewControllerB.I tried adding CGAffineTransform to ViewControllerB, but the image is getting more zoomed.Please help me achieve the image in exact same scaled, panned and rotated value on View controller B.Thanks.

ViewControllerA -

    class ViewControllerA: UIViewController {
var imageViewToTest = UIImageView()
    override func viewDidLoad() {
            super.viewDidLoad() 
            createCanvas()
    }

@IBAction func backBtnCanvas(_ sender: UIButton) {
let VC = self.storyboard?.instantiateViewController(withIdentifier: "ViewControllerB") as! ViewControllerB
        VC.fetchImageViewToTest = imageViewToTest
        let window = UIApplication.shared.windows.first
        window?.rootViewController = VC
}
    func createCanvas() {
            let View1: UIView = {
                let viewView = UIView()
                viewView.translatesAutoresizingMaskIntoConstraints = false
                viewView.contentMode = .scaleAspectFit
                viewView.backgroundColor = .white
                 viewView.clipsToBounds = true
                return viewView
            }()
            self.view.addSubview(View1)
            View1.centerXAnchor.constraint(equalTo: view.centerXAnchor, constant: 0).isActive = true
            View1.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: 0).isActive = true
            View1.widthAnchor.constraint(equalTo: view..widthAnchor, constant: 0).isActive = true
            View1.heightAnchor.constraint(equalTo: view..widthAnchor, multiplier: 1.0).isActive = true
                let image_View1: UIImageView = {
                    let image_View1= UIImageView()
                    image_View1.image = image.  // Add any image you have
                    image_View1.contentMode = .scaleAspectFill
                    image_View1.translatesAutoresizingMaskIntoConstraints = false
                   image_View1.clipsToBounds = true
                    return image_View1
                }()
                View1.addSubview(image_View1)
                
               image_View1.topAnchor.constraint(equalTo: View1.topAnchor, constant: 0).isActive = true
                image_View1.bottomAnchor.constraint(equalTo: View1.bottomAnchor, constant: 0).isActive = true
                image_View1.leadingAnchor.constraint(equalTo: View1.leadingAnchor, constant: 0).isActive = true
                image_View1.trailingAnchor.constraint(equalTo: View1.trailingAnchor, constant: 0).isActive = true
    self.imageViewToTest = image_View
    let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(imageTapped(tapGestureRecognizer:)))
                    image_View1.isUserInteractionEnabled = true
                    image_View1.addGestureRecognizer(tapGestureRecognizer)
                    
                    let pinchGesture = UIPinchGestureRecognizer(target: self, action: #selector(pinchAction))
                    image_View1.addGestureRecognizer(pinchGesture)
                    
                    let rotate = UIRotationGestureRecognizer(target: self, action: #selector(rotateAction))
                    image_View1.addGestureRecognizer(rotate)
    
    if UserDefaults.standard.bool(forKey: "tapRecognizedForImage") == true {
                        createPanGestureRecognizer(targetView: image_View1)
                    }
    }
    
    @objc func imageTapped(tapGestureRecognizer: UITapGestureRecognizer) {
            UserDefaults.standard.set(true, forKey: "tapRecognizedForImage")
        }
    
    //Pan Gesture for Image
        func createPanGestureRecognizer(targetView: UIImageView) {
            let panGesture = UIPanGestureRecognizer(target: self, action:#selector(handlePanGesture))
            targetView.addGestureRecognizer(panGesture)
        }
        
        @objc func handlePanGesture(panGesture: UIPanGestureRecognizer) {
            let imageView = panGesture.view as! UIImageView
            let translation = panGesture.translation(in: view)
            panGesture.setTranslation(CGPoint.zero, in: view)
            
            self.translationX = translation.x
            self.translationY = translation.y
            
            imageView.center = CGPoint(x: imageView.center.x+translation.x, y: imageView.center.y+translation.y)
            imageView.isMultipleTouchEnabled = true
            imageView.isUserInteractionEnabled = true
     
            switch panGesture.state {
            case .began,.ended: break
            case .changed:
                self.positionX = imageView.center.x
                self.positionY = imageView.center.y
           
                break
            default:
                break
            }
        }

ViewControllerB -

    class ViewControllerB: UIViewController {
var fetchImageViewToTest = UIImageView()
    override func viewDidLoad() {
            super.viewDidLoad() 
            createCanvas()
    }
    func createCanvas() {
            let View1: UIView = {
                let viewView = UIView()
                viewView.translatesAutoresizingMaskIntoConstraints = false
                viewView.contentMode = .scaleAspectFit
                viewView.backgroundColor = .white
                 viewView.clipsToBounds = true
                return viewView
            }()
            self.view.addSubview(View1)
            View1.centerXAnchor.constraint(equalTo: view.centerXAnchor, constant: 0).isActive = true
            View1.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: 0).isActive = true
            View1.widthAnchor.constraint(equalTo: view..widthAnchor, constant: 0).isActive = true
            View1.heightAnchor.constraint(equalTo: view..widthAnchor, multiplier: 1.0).isActive = true
                let image_View1: UIImageView = {
                    let image_View1= UIImageView()
                    image_View1.image = image.  // Add any image you have
                    image_View1.contentMode = .scaleAspectFill
    image_View1.translatesAutoresizingMaskIntoConstraints = false
                   image_View1.clipsToBounds = true
                    return image_View1
                }()
                View1.addSubview(image_View1)
               image_View1.topAnchor.constraint(equalTo: View1.topAnchor, constant: 0).isActive = true
                image_View1.bottomAnchor.constraint(equalTo: View1.bottomAnchor, constant: 0).isActive = true
                image_View1.leadingAnchor.constraint(equalTo: View1.leadingAnchor, constant: 0).isActive = true
                image_View1.trailingAnchor.constraint(equalTo: View1.trailingAnchor, constant: 0).isActive = true }

[![Screenshot of what I tried in my code for ViweControllerB][1]][1] [1]: https://i.sstatic.net/1c6cX.png


Solution

  • When you create the new UIImageView in your secondViewController set it's transform equals to firstImageView.transform, which is already rotated/scaled etc. You don't have to apply CGAffineTransforms to any other view in secondViewController since you originally add the transforms to UIImageView only. firstImageView.transform has all the transformations you applied to it.

    let image_View: UIImageView = {
        let imageV = UIImageView()
        imageV.image = image
        imageV.translatesAutoresizingMaskIntoConstraints = false
        imageV.contentMode = .scaleAspectFill
        imageV.clipsToBounds = true
        imageV.transform = firstImageView.transform
        return imageV
    }()
    

    I have added a sample Swift Playground code with the idea

    import UIKit
    import PlaygroundSupport
    
    let containerView = UIView(frame: CGRect(x: 0, y: 0, width: 500, height: 600))
    
    let view1 = UIView(frame: CGRect(x: 0, y: 0, width: 500, height: 300))
    view1.backgroundColor = .systemYellow
    
    let image_view1: UIImageView = {
        let image_View1 = UIImageView()
        image_View1.frame = CGRect(x: 100, y: 100, width: 100, height: 100)
        image_View1.image = UIImage(systemName: "trash.fill")
        image_View1.contentMode = .scaleAspectFill
       image_View1.clipsToBounds = true
        return image_View1
    }()
    
    //add transforms to the image_view1 (from panGestures, rotationGesture etc)
    image_view1.transform = image_view1.transform.concatenating(CGAffineTransform(scaleX: 1.2, y: 1.2)).concatenating(CGAffineTransform(rotationAngle: 0.5))
        .concatenating(CGAffineTransform(translationX: 50, y: 50))
    
    view1.addSubview(image_view1)
    
    
    //create view2
    let view2 = UIView(frame: CGRect(x: 0, y: 300, width: 500, height: 300))
    view2.backgroundColor = .green
    
    let image_view2: UIImageView = {
        let image_view2 = UIImageView()
        image_view2.frame = CGRect(x: 100, y: 100, width: 100, height: 100)
        image_view2.image = UIImage(systemName: "trash.fill")
        //copy transforms from image_view1
        image_view2.transform = image_view1.transform
        image_view2.contentMode = .scaleAspectFill
       image_view2.clipsToBounds = true
        return image_view2
    }()
    
    view2.addSubview(image_view2)
    
    containerView.addSubview(view1)
    containerView.addSubview(view2)
    
    PlaygroundPage.current.liveView = containerView
    

    Below is how it looks like in Playground when you run this. The yellow view has the image_view1 with transformations and green view creates a new image_view2 and use the transforms from the image_view1

    enter image description here