Зробити простий затухання в анімації в Swift?


82

Я намагаюся зробити просту анімацію в Swift. Це затухання.

Я спробував:

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

Тоді я маю:

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

І потім:

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

У мене все це є в моїй функції viewDidLoad.

Як мені зробити цю роботу?


Всі елементи входять одночасно. Прямо при завантаженні подання.
Benr783

Ви впевнені, що погляди правильно підключені в xib?
drewag

Я не використовую IB. Все програмно.
Benr783

Ну з коду, який ви надали, все повинно працювати (і це не має нічого спільного зі Swift). Має бути десь ще помилка.
drewag

Подумайте про переміщення виклику методу вигляду видів, viewWillAppearабо viewDidAppearякщо ви не знаєте, що відбувається між видом, який завантажується та відображається.
A-Live

Відповіді:


121

Проблема в тому, що ви намагаєтеся запустити анімацію занадто рано в життєвому циклі контролера перегляду. У viewDidLoad, подання щойно створене і ще не додане до ієрархії подання, тому спроба анімувати одне з його subviewsна даний момент дає погані результати.

Що ви дійсно повинні робити, це продовжувати встановлювати альфа-перегляд у viewDidLoad(або там, де ви створюєте свої погляди), а потім чекати, поки 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
    }
}

Чи це viewWillAppearбільше підходить для цього?
тон

1
Пам'ятайте, якщо у вас є лише 1 виписка, вам потрібно додати поверненняUIView.animateWithDuration(1.5, animations: { self.myFirstLabel.alpha = 1.0 return })
ошеванс

@oshevans Ви маєте на увазі необхідність додати заяву про повернення в кінці закриття? Це було в основному виправлено в найновіших версіях Xcode.
Mick MacCallum

У мене дуже схожа помилка. Будь ласка , якщо ви можете мені допомогти: stackoverflow.com/questions/29910669 / ...
Teo Інке

@ 0x7fffffff '... в основному виправлено ...' - це не звучить багатообіцяюче; / Ще оновити з 6.2
ошеван

46

0x7ffffff нормальна і, безумовно, вичерпна.

Як плюс, я пропоную вам зробити розширення 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
    })
  }

}

Стрім-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
    })
}

Таким чином ви можете зробити це скрізь, де знаходиться ваш код:

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

Повторне використання коду важливо!


7

Швидке рішення

Подібно до анкера Луки , я використовую 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)
  }
}

Як користуватися ним:

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

5

Якщо ви хочете повторювану затухаючу анімацію, ви можете зробити це, використовуючи, CABasicAnimationяк показано нижче:

Спочатку створіть зручне розширення 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)
    }
}

Як користуватися ним:

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

Стрімкий 5

Інші відповіді правильні, але в моєму випадку мені потрібно звертатися з іншими властивостями і ( 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)
        }
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.