Make a simple fade in animation in Swift?

前端 未结 6 1017
一个人的身影
一个人的身影 2021-01-30 08:08

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

I attempted:

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


        
相关标签:
6条回答
  • 2021-01-30 08:27

    Swift only solution

    Similar to Luca's anwer, I use a UIView extension. Compared to his solution I use DispatchQueue.main.async to make sure animations are done on the main thread, alpha parameter for fading to a specific value and optional duration parameters for cleaner code.

    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)
    
    0 讨论(0)
  • 2021-01-30 08:29

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

    First create handy UIView extension :

    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)
    
    0 讨论(0)
  • 2021-01-30 08:51

    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 subviews at this point produces bad results.

    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.

    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
        }
    }
    
    0 讨论(0)
  • 2021-01-30 08:51

    Swift 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:

    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)
            }
        }
    }
    
    0 讨论(0)
  • 2021-01-30 08:53

    0x7ffffff's answer is ok and definitely exhaustive.

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

    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

    /// 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!

    0 讨论(0)
  • 2021-01-30 08:53
    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")
        }
    
    }
    
    0 讨论(0)
提交回复
热议问题