Search code examples
iosswiftanimationuiimageview

iOS - Card flip animation


I have two UIImageViews. One is the 'Front' and the other is the 'Back'. I'm trying to implement it so that when you click onto the 'Back' it will trigger the animation and flip the card.

The animation works perfectly. But it animates the full page, which I don't want. I only want the UIImageView to flip. I can't see what I'm doing wrong. Probably something obvious.

@IBOutlet weak var answerImageViewer: UIImageView?
@IBOutlet weak var backAnswerImageViewer: UIImageView?

override func viewDidLoad() {
    super.viewDidLoad()
    startNewGame()
    retrieveNewQuestion()
    setupBannerMessage()
    customPlayButtons()

    let tapGesture = UITapGestureRecognizer(target: self, action: Selector("tap"))
    tapGesture.numberOfTapsRequired = 1
    backAnswerImageViewer?.addGestureRecognizer(tapGesture)
    backAnswerImageViewer?.userInteractionEnabled = true
}

var showingBack = true

func tap (){
    if showingBack{
       UIView.transitionFromView(self.backAnswerImageViewer!, toView: self.answerImageViewer!, duration: 1, options: UIViewAnimationOptions.TransitionFlipFromRight, completion: nil)

        backAnswerImageViewer?.hidden = true
        answerImageViewer?.hidden = false

        showingBack = false
    }
    else {
        showingBack = true

        UIView.transitionFromView(self.answerImageViewer!, toView: self.backAnswerImageViewer!, duration: 1, options: UIViewAnimationOptions.TransitionFlipFromRight, completion: nil)

        backAnswerImageViewer?.hidden = false
        answerImageViewer?.hidden = true
    }
}

Solution

  • Your problem is that your UIImageViews are directly on the "full page" view.

    transitionFromView removes the fromView from its superview and adds the toView on the superview with the given animation. Thus, it animates the superview.

    You should include a UIView that servers as a container and have both imageViews as subviews. Add your tap gesture on the containerview. Also, you should not have weak references to the imageViews, since once you have done the animation once, your reference to the back imageView will be gone. It is probably better to add these in code rather than storyboard. No need to hide the imageViews.

    Here are some sample code:

    class MyViewController: UIViewController {
    
            @IBOutlet weak var containerView: UIView!
    
            private let backImageView: UIImageView! = UIImageView(image: UIImage(named: "back"))
            private let frontImageView: UIImageView! = UIImageView(image: UIImage(named: "front"))
    
            private var showingBack = false
    
            override func viewDidLoad() {
                super.viewDidLoad()
    
                frontImageView.contentMode = .ScaleAspectFit
                backImageView.contentMode = .ScaleAspectFit
    
                containerView.addSubview(frontImageView)
                frontImageView.translatesAutoresizingMaskIntoConstraints = false
                frontImageView.spanSuperview()
    
                let singleTap = UITapGestureRecognizer(target: self, action: #selector(flip))
                singleTap.numberOfTapsRequired = 1
                containerView.addGestureRecognizer(singleTap)
            }
    
            func flip() {   
                let toView = showingBack ? frontImageView : backImageView
                let fromView = showingBack ? backImageView : frontImageView
                UIView.transitionFromView(fromView, toView: toView, duration: 1, options: .TransitionFlipFromRight, completion: nil)
                toView.translatesAutoresizingMaskIntoConstraints = false
                toView.spanSuperview()
                showingBack = !showingBack
            }   
    
        }