Search code examples
iosswiftuiviewuiimageviewcore-animation

Animate UIImageView appearing on screen line by line


I'd like to display a UIImageView with some animation and i'm thinking i'd like for it to appear on the screen pixel by pixel moving left to right, line by line. A bit like a printer would print an image. I haven't got a clue where to start with this.

I was thinking maybe overlay the UIImageView with another view that can use animation to become transparent, but how can I make it happen?


Solution

  • Well one idea is, we have one view on top of your image, covering it entirely. Let's call this view V. Move that view down by 1 point, so a line of your image is exposed. Then have another view on top of your image, covering it entirely again. Let's call this view H. Then move that view right by 1 point. Now one "pixel" (or rather, a 1x1 point grid) of your image is exposed.

    We'll animate H to the right. When it reaches the end, we'll put it back where it started, move V and H down by 1 point, and repeat the process.

    Here's something to get you started.

    extension UIView {
    
        /**
         - Parameter seconds: the time for one line to reveal
         */
        func scanReveal(seconds: Double) {
    
            let colour = self.superview?.backgroundColor ?? UIColor.black
    
            let v = UIView(frame: self.bounds)
            v.backgroundColor = colour
            self.addSubview(v)
    
            let h = UIView(frame: self.bounds)
            h.backgroundColor = colour
            self.addSubview(h)
    
            v.frame.origin.y += 1
    
            // Animate h to the end.
            // When it reaches the end, bring it back, move v and h down by 1 and repeat.
    
            func move() {
                UIView.animate(withDuration: seconds, animations: {
                    h.frame.origin.x = h.bounds.height
                }) { _ in
                    h.frame.origin.x = 0
                    h.frame.origin.y += 1
                    v.frame.origin.y += 1
    
                    if v.frame.origin.y > self.bounds.height {
                        return
                    }
                    move()
                }
            }
            move()
        }
    }