簡體   English   中英

自定義UIView:延遲子圖層動畫

[英]Custom UIView: animate subLayers with delay

我想創建一個自定義UIView子類,該子類代表深藍色天空中的一堆星星。

因此,我創建了以下視圖:

import UIKit

class ConstellationView: UIView {

    // MARK: - Properties
    @IBInspectable var numberOfStars: Int = 80
    @IBInspectable var animated: Bool = false

    // Private properties
    private var starsToDraw = [CAShapeLayer]()

    // Layers
    private let starsLayer = CAShapeLayer()



    // MARK: - Drawing
    //    override func drawRect(rect: CGRect) {
    override func layoutSubviews() {

        // Generate stars
        drawStars(rect: self.bounds)

    }



    /// Generate stars
    func drawStars(rect: CGRect) {

        let width = rect.size.width
        let height = rect.size.height
        let screenBounds = UIScreen.main.bounds

        // Create the stars and store them in starsToDraw array
        for _ in 0 ..< numberOfStars {
            let x = randomFloat() * width
            let y = randomFloat() * height
            // Calculate the thinness of the stars as a percentage of the screen resolution
            let thin: CGFloat = max(screenBounds.width, screenBounds.height) * 0.003 * randomFloat()
            let starLayer = CAShapeLayer()
            starLayer.path = UIBezierPath(ovalIn: CGRect(x: x, y: y, width: thin, height: thin)).cgPath
            starLayer.fillColor = UIColor.white.cgColor
            starsToDraw.append(starLayer)
        }


        // Define a fade animation
        let appearAnimation = CABasicAnimation(keyPath: "opacity")
        appearAnimation.fromValue = 0.2
        appearAnimation.toValue = 1
        appearAnimation.duration = 1
        appearAnimation.fillMode = kCAFillModeForwards

        // Add the animation to each star (if animated)
        for (index, star) in starsToDraw.enumerated() {

            if animated {
                // Add 1 s between each animation
                appearAnimation.beginTime = CACurrentMediaTime() + TimeInterval(index)
                star.add(appearAnimation, forKey: nil)
            }

            starsLayer.insertSublayer(star, at: 0)
        }

        // Add the stars layer to the view layer
        layer.insertSublayer(starsLayer, at: 0)
    }


    private func randomFloat() -> CGFloat {
        return CGFloat(arc4random()) / CGFloat(UINT32_MAX)
    }

}

它工作得很好,結果如下: 在此處輸入圖片說明

但是,我想讓它動起來,也就是說,這80顆星星中的每一顆都應該一個接一個地出現,並且要延遲1秒。

我試圖增加動畫的beginTime ,但似乎並沒有達到目的。 我檢查了drawRectlayoutSubviews ,但沒有區別。

你可以幫幫我嗎 ?

謝謝

PS:要重現我的應用程序,只需在XCode中創建一個新的單視圖應用程序,使用此代碼創建一個新文件,然后將ViewController的視圖設置為ConstellationView,並使用深色背景色。 還要在Interface Builder或代碼中將animated屬性設置為true。

PPS:這是在Swift 3中,但我認為它仍然可以理解:-)

您真的很親密,只有兩件事要做!

首先,在將動畫添加到圖層時需要指定關鍵點。

star.add(appearAnimation, forKey: "opacity")

其次,動畫的填充模式需要為kCAFillModeBackwards而不是kCAFillModeForwards

有關更詳細的參考,請參見-https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CoreAnimation_guide/AdvancedAnimationTricks/AdvancedAnimationTricks.html

這里還有一個有趣的教程(與CAAnimations實踐!) - https://www.raywenderlich.com/102590/how-to-create-a-complex-loading-animation-in-swift

希望這可以幫助😀

完整代碼:

class ConstellationView: UIView {

  // MARK: - Properties
  @IBInspectable var numberOfStars: Int = 80
  @IBInspectable var animated: Bool = true

  // Private properties
  private var starsToDraw = [CAShapeLayer]()

  // Layers
  private let starsLayer = CAShapeLayer()

  override func awakeFromNib() {
    super.awakeFromNib()
  }

  // MARK: - Drawing
  override func layoutSubviews() {
    // Generate stars
    drawStars(rect: self.bounds)
  }

  /// Generate stars
  func drawStars(rect: CGRect) {
    let width = rect.size.width
    let height = rect.size.height
    let screenBounds = UIScreen.main.bounds

    // Create the stars and store them in starsToDraw array
    for _ in 0 ..< numberOfStars {
      let x = randomFloat() * width
      let y = randomFloat() * height
      // Calculate the thinness of the stars as a percentage of the screen resolution
      let thin: CGFloat = max(screenBounds.width, screenBounds.height) * 0.003 * randomFloat()
      let starLayer = CAShapeLayer()
      starLayer.path = UIBezierPath(ovalIn: CGRect(x: x, y: y, width: thin, height: thin)).cgPath
      starLayer.fillColor = UIColor.white.cgColor
      starsToDraw.append(starLayer)
    }

    // Define a fade animation
    let appearAnimation = CABasicAnimation(keyPath: "opacity")
    appearAnimation.fromValue = 0.2
    appearAnimation.toValue = 1
    appearAnimation.duration = 1
    appearAnimation.fillMode = kCAFillModeBackwards

    // Add the animation to each star (if animated)
    for (index, star) in starsToDraw.enumerated() {  
      if animated {
        // Add 1 s between each animation
        appearAnimation.beginTime = CACurrentMediaTime() + TimeInterval(index)
        star.add(appearAnimation, forKey: "opacity")
      }
      starsLayer.insertSublayer(star, above: nil)
    }

    // Add the stars layer to the view layer
    layer.insertSublayer(starsLayer, above: nil)
  }

  private func randomFloat() -> CGFloat {
    return CGFloat(arc4random()) / CGFloat(UINT32_MAX)
  }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM