Search code examples
iosswiftanimationscaling

How to scale a UIView from left to right and back?


I want to have an UIView to appear by scaling from left to right if I hit a button. If I hit the button again, the view should scale away from right to left.

I found an explanation how to do it for left to right, but even this solution is working only once. If I hide the view and play the animation again it scales it from the centre again. Also scaling it back from right to left doesn't work either as it disappears immdiatly without any animation.

Here's my code so far:

if(!addQuestionaryView.isHidden)
    {
        //Reset input if view is hidden
        addQuestionaryInput.text = ""
        self.addQuestionaryView.isHidden = false
        let frame = addQuestionaryView.frame;
        let rect = CGRect(x: frame.origin.x, y: frame.origin.y, width: frame.width, height: frame.height)
        let leftCenter = CGPoint(x: rect.minX, y: rect.minY)
        addQuestionaryView.layer.anchorPoint = CGPoint(x:1,y: 0.5)
        addQuestionaryView.layer.position = leftCenter
        UIView.animate(withDuration: 0.6,
                       animations: {
                        self.addQuestionaryView.transform = CGAffineTransform(scaleX: 0, y: 1)
        },
                       completion: { _ in
                        self.addQuestionaryView.isHidden = true
        })
    }
    else
    {
        self.addQuestionaryView.isHidden = false
        let frame = addQuestionaryView.frame;
        let rect = CGRect(x: frame.origin.x, y: frame.origin.y, width: frame.width, height: frame.height)
        let leftCenter = CGPoint(x: rect.minX, y: rect.midY)
        addQuestionaryView.layer.anchorPoint = CGPoint(x:0,y: 0.5);
        addQuestionaryView.layer.position = leftCenter
        addQuestionaryView.transform = CGAffineTransform(scaleX: 0, y: 1)
        UIView.animate(withDuration: 0.6,
                       animations: {
                        self.addQuestionaryView.transform = CGAffineTransform(scaleX: 1, y: 1)
        },
                       completion: nil)
    }

As said the appearing part works once and then starts from the centre again. The disappearing part doesn't work at all.


Solution

  • I don't know what "to scale it so it has a little look like Android reveal animations" means (and I hope I never do; I've never seen an Android phone, I never hope to see one).

    But do you mean something like this? This is done by animating a mask in front of the view, thus revealing and then hiding it:

    enter image description here

    Here's the code used in that example:

    class MyMask : UIView {
        override func draw(_ rect: CGRect) {
            let r = CGRect(x: 0, y: 0, width: rect.width/2.0, height: rect.height)
            UIColor.black.setFill()
            UIGraphicsGetCurrentContext()?.fill(r)
        }
    }
    
    class ViewController: UIViewController {
    
        @IBOutlet weak var lab: UILabel!
        var labMaskOrigin = CGPoint.zero
    
        var didAddMask = false
        override func viewDidLayoutSubviews() {
            if didAddMask {return}
            didAddMask = true
            let mask = MyMask()
            mask.isOpaque = false
            let w = self.lab.bounds.width
            let h = self.lab.bounds.height
            mask.frame = CGRect(x: -w, y: 0, width: w*2, height: h)
            self.lab.mask = mask
            self.labMaskOrigin = mask.frame.origin
        }
    
        var labVisible = false
        func toggleLabVisibility() {
            labVisible = !labVisible
            UIView.animate(withDuration: 5) {
                self.lab.mask!.frame.origin = self.labVisible ?
                    .zero : self.labMaskOrigin
            }
        }
    }