ios 在 Swift 中制作一个简单的淡入淡出动画?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24111770/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 00:41:43  来源:igfitidea点击:

Make a simple fade in animation in Swift?

iosswift

提问by Benr783

I am trying to make a simple animation in Swift. It is a fade in.

我正在尝试在 Swift 中制作一个简单的动画。这是一个淡入。

I attempted:

我尝试:

self.myFirstLabel.alpha = 0
self.myFirstButton.alpha = 0
self.mySecondButton.alpha = 0

Then, I have:

然后,我有:

self.view.addSubview(myFirstLabel)
self.view.addSubview(myFirstButton)
self.view.addSubview(mySecondButton)

And then:

进而:

UIView.animateWithDuration(1.5, animations: {
 self.myFirstLabel.alpha = 1.0
 self.myFirstButton.alpha = 1.0
 self.mySecondButton.alpha = 1.0
})

I have all of this in my viewDidLoad function.

我的 viewDidLoad 函数中包含所有这些。

How do I make this work?

我如何使这项工作?

回答by Mick MacCallum

The problem is that you're trying start the animation too early in the view controller's lifecycle. In viewDidLoad, the view has just been created, and hasn't yet been added to the view hierarchy, so attempting to animate one of its subviewsat this point produces bad results.

问题是您试图在视图控制器的生命周期中过早地启动动画。在 中viewDidLoad,视图刚刚创建,尚未添加到视图层次结构中,因此此时尝试为其之一设置动画subviews会产生不好的结果。

What you really should be doing is continuing to set the alpha of the view in viewDidLoad(or where you create your views), and then waiting for the viewDidAppear: method to be called. At this point, you can start your animations without any issue.

您真正应该做的是继续在viewDidLoad(或您创建视图的位置)中设置视图的 alpha ,然后等待viewDidAppear: 方法被调用。此时,您可以毫无问题地开始动画。

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    UIView.animate(withDuration: 1.5) {
        self.myFirstLabel.alpha = 1.0
        self.myFirstButton.alpha = 1.0
        self.mySecondButton.alpha = 1.0
    }
}

回答by Luca Davanzo

0x7ffffff's answer is ok and definitely exhaustive.

0x7ffffff的回答没问题,而且绝对详尽。

As a plus, I suggest you to make an UIView extension, in this way:

另外,我建议您以这种方式制作 UIView 扩展:

public extension UIView {

  /**
  Fade in a view with a duration

  - parameter duration: custom animation duration
  */
  func fadeIn(duration duration: NSTimeInterval = 1.0) {
    UIView.animateWithDuration(duration, animations: {
        self.alpha = 1.0
    })
  }

  /**
  Fade out a view with a duration

  - parameter duration: custom animation duration
  */
  func fadeOut(duration duration: NSTimeInterval = 1.0) {
    UIView.animateWithDuration(duration, animations: {
        self.alpha = 0.0
    })
  }

}

Swift-3

斯威夫特-3

/// Fade in a view with a duration
/// 
/// Parameter duration: custom animation duration
func fadeIn(withDuration duration: TimeInterval = 1.0) {
    UIView.animate(withDuration: duration, animations: {
        self.alpha = 1.0
    })
}

/// Fade out a view with a duration
///
/// - Parameter duration: custom animation duration
func fadeOut(withDuration duration: TimeInterval = 1.0) {
    UIView.animate(withDuration: duration, animations: {
        self.alpha = 0.0
    })
}

In this way you can do this wherever in your code:

通过这种方式,您可以在代码中的任何位置执行此操作:

let newImage = UIImage(named: "")
newImage.alpha = 0 // or newImage.fadeOut(duration: 0.0)
self.view.addSubview(newImage)
... 
newImage.fadeIn()

Code reuse is important!

代码重用很重要!

回答by budidino

Swiftonly solution

Swift唯一的解决方案

Similar to Luca's anwer, I use a UIViewextension. Compared to his solution I use DispatchQueue.main.asyncto make sure animations are done on the main thread, alphaparameter for fading to a specific value and optional durationparameters for cleaner code.

Luca 的 anwer类似,我使用了UIView扩展名。与他的解决方案相比,我DispatchQueue.main.async用来确保在主线程上完成动画、alpha用于淡入淡出到特定值的duration参数和用于更清晰代码的可选参数。

extension UIView {
  func fadeTo(_ alpha: CGFloat, duration: TimeInterval = 0.3) {
    DispatchQueue.main.async {
      UIView.animate(withDuration: duration) {
        self.alpha = alpha
      }
    }
  }

  func fadeIn(_ duration: TimeInterval = 0.3) {
    fadeTo(1.0, duration: duration)
  }

  func fadeOut(_ duration: TimeInterval = 0.3) {
    fadeTo(0.0, duration: duration)
  }
}

How to use it:

如何使用它:

// fadeIn() - always animates to alpha = 1.0
yourView.fadeIn()     // uses default duration of 0.3
yourView.fadeIn(1.0)  // uses custom duration (1.0 in this example)

// fadeOut() - always animates to alpha = 0.0
yourView.fadeOut()    // uses default duration of 0.3
yourView.fadeOut(1.0) // uses custom duration (1.0 in this example)

// fadeTo() - used if you want a custom alpha value
yourView.fadeTo(0.5)  // uses default duration of 0.3
yourView.fadeTo(0.5, duration: 1.0)

回答by cs4alhaider

If you want repeatable fade animation you can do that by using CABasicAnimationlike below :

如果您想要可重复的淡入淡出动画,您可以使用CABasicAnimation如下所示:

First create handy UIView extension :

首先创建方便的 UIView 扩展:

extension UIView {

    enum AnimationKeyPath: String {
        case opacity = "opacity"
    }

    func flash(animation: AnimationKeyPath ,withDuration duration: TimeInterval = 0.5, repeatCount: Float = 5){
        let flash = CABasicAnimation(keyPath: animation.rawValue)
        flash.duration = duration
        flash.fromValue = 1 // alpha
        flash.toValue = 0 // alpha
        flash.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
        flash.autoreverses = true
        flash.repeatCount = repeatCount

        layer.add(flash, forKey: nil)
    }
}

How to use it:

如何使用它:

    // You can use it with all kind of UIViews e.g. UIButton, UILabel, UIImage, UIImageView, ...
    imageView.flash(animation: .opacity, withDuration: 1, repeatCount: 5)
    titleLabel.flash(animation: .opacity, withDuration: 1, repeatCount: 5)

回答by LLIAJLbHOu

import UIKit

/*
 Here is simple subclass for CAAnimation which create a fadeIn animation
 */

class FadeInAdnimation: CABasicAnimation {
    override init() {
        super.init()
        keyPath = "opacity"
        duration = 2.0
        fromValue = 0
        toValue = 1
        fillMode = CAMediaTimingFillMode.forwards
        isRemovedOnCompletion = false
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
}

/*
 Example of usage
 */

class ViewController: UIViewController {

    weak var label: UILabel!

    override func loadView() {
        let view = UIView()
        view.backgroundColor = .white

        let label = UILabel()
        label.alpha = 0
        label.frame = CGRect(x: 150, y: 200, width: 200, height: 20)
        label.text = "Hello World!"
        label.textColor = .black
        view.addSubview(label)
        self.label = label

        let button = UIButton(type: .custom)
        button.frame = CGRect(x: 0, y: 250, width: 300, height: 100)
        button.setTitle("Press to Start FadeIn", for: UIControl.State())
        button.backgroundColor = .red
        button.addTarget(self, action: #selector(startFadeIn), for: .touchUpInside)
        view.addSubview(button)

        self.view = view
    }

    /*
     Animation in action
     */
    @objc private func startFadeIn() {
        label.layer.add(FadeInAdnimation(), forKey: "fadeIn")
    }

}

回答by nahung89

Swift 5

斯威夫特 5

Other answers are correct, but in my case I need to handle other properties also (alpha, animate, completion). Because of this, I modified a bit to expose these parameters as below:

其他答案是正确的,但就我而言,我还需要处理其他属性 ( alpha, animate, completion)。因此,我修改了一些以公开这些参数,如下所示:

extension UIView {
    /// Helper function to update view's alpha with animation
    /// - Parameter alpha: View's alpha
    /// - Parameter animate: Indicate alpha changing with animation or not
    /// - Parameter duration: Indicate time for animation
    /// - Parameter completion: Completion block after alpha changing is finished
    func set(alpha: CGFloat, animate: Bool, duration: TimeInterval = 0.3, completion: ((Bool) -> Void)? = nil) {
        let animation = { (view: UIView) in
            view.alpha = alpha
        }

        if animate {
            UIView.animate(withDuration: duration, animations: {
                animation(self)
            }, completion: { finished in
                completion?(finished)
            })
        } else {
            layer.removeAllAnimations()
            animation(self)
            completion?(true)
        }
    }
}