Reputation: 219
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
}
}
Upvotes: 16
Views: 30984
Reputation: 13043
If you have a button
that holds "card" as a variable, and you want to change his image to a new image called "1". All you have to do is this:
let image = UIImage(named: "1")
card.setImage(image, for: .normal)
UIView.transition(with: card, duration: 2, options: .transitionFlipFromRight, animations: nil, completion: nil)
Upvotes: 24
Reputation: 832
You can use this code
UIView.transition(with: self.yourViewName, duration: 0.5, options: [.transitionFlipFromRight], animations: nil, completion: nil)
Upvotes: 3
Reputation: 425
For Swift 4
Its best to use UIButton rather than UIImageView!
var isBackImageOpen = false
if isBackImageOpen {
isBackImageOpen = false
let image = UIImage(named: "backImage")
myBtn.setImage(image, for: .normal)
UIView.transition(with: myBtn, duration: 0.3, options: .transitionFlipFromLeft, animations: nil, completion: nil)
} else {
isBackImageOpen = true
let image = UIImage(named: "frontImage")
myBtn.setImage(image, for: .normal)
UIView.transition(with: myBtn, duration: 0.3, options: .transitionFlipFromRight, animations: nil, completion: nil)
}
Hope this answer helps :)!
Upvotes: 4
Reputation: 619
According to Pankaj's answer,
In iOS 12 usage of UIView.transition method is deprecated a little bit.
In iOS 12 device, although I've updated the code from Swift 4.0 to Swift 4.2, I encountered flipping card problem.
You might mis this because; somehow, Xcode don't suggest to change this. I realized this (thanks to Intellisense), when I've tried to rewrite UIView.transition method.
Before:
UIView.transition(with: cardView, duration: 1.0, options: transitionOptions, animations: {
self.cardView.isHidden = true
self.downButtonForBackCard.alpha = 1
})
UIView.transition(with: backCardView, duration: 1.0, options: transitionOptions, animations: {
self.backCardView.isHidden = false
})
After:
UIView.transition(with: cardView, duration: 1.0, options: transitionOptions, animations: {
self.downButtonForBackCard.alpha = 1
}) { (finish) in
self.cardView.isHidden = true
}
UIView.transition(with: backCardView, duration: 1.0, options: transitionOptions, animations: {
self.backCardView.isHidden = false
}) { (finish) in
}
PS: Those two codes are all from my case. Don't copy paste, just take example.
I hope I can save someones's life.
Upvotes: 3
Reputation: 3936
The previous answer are good but add 'showHideTransitionViews' as an options, it allows you to not have manually hide and shows the views that is animated. Just keep in mind that those two views need to be inside an other view. This transition will rotate the super view.
UIView.transition(from: view1, to: view2, duration: 0.5, options: [.transitionFlipFromLeft, .showHideTransitionViews], completion: nil)
Upvotes: -1
Reputation: 3907
Try this extension maybe it's easy to use
extension UIView{
func showFlip(){
if self.isHidden{
UIView.transition(with: self, duration: 1, options: [.transitionFlipFromRight,.allowUserInteraction], animations: nil, completion: nil)
self.isHidden = false
}
}
func hideFlip(){
if !self.isHidden{
UIView.transition(with: self, duration: 1, options: [.transitionFlipFromLeft,.allowUserInteraction], animations: nil, completion: nil)
self.isHidden = true
}
}
}
use this in click action
func Flip(){
if second_view.isHidden == true{
second_view.showFlip()
first_view.hideFlip()
}else if first_view.isHidden == true{
second_view.hideFlip()
first_view.showFlip()
}
}
Upvotes: 0
Reputation: 9897
This solution is for flipping "a card", using two UIImageView
(just like you are using...), I am using it inside a UICollectionView, that that is of course not neccessary.
class CardCVCell: UICollectionViewCell {
@IBOutlet weak var cardFrontImageView: UIImageView!
@IBOutlet weak var cardBackImageView: UIImageView!
private var flipped: Bool = false {
didSet {
cardFrontImageView.visible = flipped
cardBackImageView.hidden = flipped
}
}
override func awakeFromNib() {
super.awakeFromNib()
cardBackImageView.backgroundColor = UIColor.brownColor()
}
override func prepareForReuse() {
super.prepareForReuse()
cardFrontImageView.image = nil
flipped = false
}
func flipCard(cardModel: Card) {
let flipped = cardModel.flipped
let fromView = flipped ? cardFrontImageView : cardBackImageView
let toView = flipped ? cardBackImageView : cardFrontImageView
let flipDirection: UIViewAnimationOptions = flipped ? .TransitionFlipFromRight : .TransitionFlipFromLeft
let options: UIViewAnimationOptions = [flipDirection, .ShowHideTransitionViews]
UIView.transitionFromView(fromView, toView: toView, duration: 0.6, options: options) {
finished in
cardModel.flipped = !flipped
}
}
}
The code is taken from my open source project introducing people to Swift development, called SwiftIntro which is a memory game, fetching images from Instagram.
Please observe that the model Card must be a class and not a value type
Upvotes: 8
Reputation: 2873
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
}
}
Upvotes: 17
Reputation: 1286
You need to have a container view. Put answerImageViewer
and backAnswerImageViewer
into one single UIView
. Here's my sample code.
let frontView = UIView()
let backView = UIView()
let frame = CGRect(x: 40, y: 100, width: 300, height: 400)
frontView.backgroundColor = .red
backView.backgroundColor = .blue
frontView.frame = CGRect(x: 0, y: 0, width: 300, height: 400)
backView.frame = CGRect(x: 0, y: 0, width: 300, height: 400)
let containerView = UIView()
containerView.frame = frame
containerView.addSubview(backView)
containerView.addSubview(frontView)
view.addSubview(containerView)
Upvotes: 3