iOS - 卡片翻转动画

16

我有两个UIImageView。一个是“Front” ,另一个是“Back” 。 我试图实现这样的效果,当你点击“Back”时,它会触发动画并翻转卡片。

动画效果完美。但它会对整个页面进行动画处理,这不是我想要的。我只想让UIImageView 翻转。我看不出我做错了什么,可能是一些明显的错误。

@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
    }
}

你说的“动画整个页面”是什么意思?能提供一张截图吗? - wint
不要只是UIImageView翻转,而是让视图控制器进行翻转。 - Scott B
你应该使用 UIView.AnimationOptions showHideTransitionViews - onmyway133
9个回答

22

如果您有一个名为 button 的按钮,它以变量“card”保存,并且您想将其图像更改为名为“1”的新图像。您所需做的就是:

let image = UIImage(named: "1")
card.setImage(image, for: .normal)
UIView.transition(with: card, duration: 2, options: .transitionFlipFromRight, animations: nil, completion: nil)

2
如此简单的解决方案。我在即将推出的闪卡应用程序中实现了它。我添加了一个布尔值以便在翻转之间进行切换。 "如果 isFlipped {          UIView.transition(with:flashcardView,duration:0.5,options:.transitionFlipFromRight,animations:nil,completion:nil)     isFlipped = false      } else {    UIView.transition(with:flashcardView,duration:0.5,options:.transitionFlipFromLeft,animations:nil,completion:nil)     isFlipped = true }" - user1531352
当我尝试这段代码时,图像只会在翻转之后设置,而不是在翻转的过程中... - Tulleb

17

你的问题在于UIImageView直接放在了“全屏”视图上。

transitionFromView会将fromView从其父视图中移除,并以给定动画添加toView到父视图中。因此,它对父视图进行动画处理。

你应该包含一个充当容器的UIView,并将两个imageView作为其子视图。在containerview上添加tap手势。此外,由于一旦完成动画后,对背面imageView的引用将消失,因此不应该使用imageView的弱引用。最好在代码中添加它们而不是在storyboard中。无需隐藏imageView。

以下是一些示例代码:

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
        }   

    }

8

这个解决方案是用两个UIImageView(就像你正在使用的那样...)翻转"一张卡片"。我将其用在了一个UICollectionView中,但这当然不是必须的。

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
        }
    }
}

这段代码来自于我的开源项目SwiftIntro,介绍人们如何开发Swift,这个项目是一个内存游戏,从Instagram获取图片。

请注意,Card模型必须是一个类而不是值类型。


2
我的整个UIView都在旋转,而不是UIImageview :( - Yaroslav Dukal
整个视图控制器都在翻转,即使我只将我的UI视图设置为transitionFromView:toView:duration。有什么想法吗? - David Seek
@david-seek 你确定你没有意外地将 toViewfromView 设置为了 view (self.view) 吗? :S - Sajjon
非常确定。但是以下线程指出,您需要将视图显式放入新的子视图容器中,否则VC也会翻转。https://dev59.com/XoXca4cB1Zd3GeqPI3zb - David Seek
我不明白为什么,但那似乎是解决方案。 - David Seek
显示剩余4条评论

4

对于Swift 4

最好使用UIButton而不是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)
}

希望这个答案能帮到你 :)!

3
您可以使用这段代码。
UIView.transition(with: self.yourViewName, duration: 0.5, options: [.transitionFlipFromRight], animations: nil, completion: nil)

1
Dont copy paste answers - J. Doe

3

您需要一个容器视图。将answerImageViewerbackAnswerImageViewer放入一个单独的UIView中。以下是我的示例代码。

    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)

3
根据Pankaj的回答,iOS 12中UIView.transition方法的使用略有过时。在iOS 12设备上,虽然我已经将代码从Swift 4.0更新到Swift 4.2,但我遇到了翻转卡片的问题。你可能会错过这一点,因为某种原因,Xcode没有建议更改这个。当我尝试重写UIView.transition方法时,我意识到了这一点(感谢智能提示)。之前的代码如下:
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
    })

之后:

 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:这两个代码都来自我的案例。请勿复制粘贴,仅作为示例。

我希望我可以帮助某些人解决问题。


0

试试这个扩展,可能很容易使用

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
        }
    }
}

在点击操作中使用此代码。
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()
        }
}

-1
之前的回答都很好,但是可以添加 'showHideTransitionViews' 作为一个选项,它允许您不必手动隐藏和显示被动画的视图。只需记住这两个视图需要在另一个视图内部。此过渡将旋转父视图。
  UIView.transition(from: view1, to: view2, duration: 0.5, options: [.transitionFlipFromLeft, .showHideTransitionViews], completion: nil)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接