swift實現顏色漸變以及轉換動畫

本文是通過結合使用CAGradientLayer、CABasicAnimation以及CAAnimationDelegate來達到顏色漸變以及轉換的動畫,下面是今天要達成的效果圖:

首先創建一個CAGradientLayer和幾個自己喜歡的顏色,讓VC持有。

let colorOne = #colorLiteral(red: 0.2392156869, green: 0.6745098233, blue: 0.9686274529, alpha: 1).cgColor
let colorTwo = #colorLiteral(red: 0.8078431487, green: 0.02745098062, blue: 0.3333333433, alpha: 1).cgColor
let colorThree = #colorLiteral(red: 0.9607843161, green: 0.7058823705, blue: 0.200000003, alpha: 1).cgColor
let gradient = CAGradientLayer()

接下來為gradient賦值,將其frame等同於視圖的大小,然後顏色先設置為colorOne和colorTwo,起始點和結束點分別為CGPoint(x:0, y:0)和CGPoint(x:1, y:1),並設置讓其在後臺線程異步繪制,最後添加到view的layer的sublayer中。

gradient.frame = self.view.bounds
gradient.colors = [colorOne,colorTwo]
gradient.startPoint = CGPoint(x:0, y:0)
gradient.endPoint = CGPoint(x:1, y:1)
gradient.drawsAsynchronously = true
self.view.layer.insertSublayer(gradient, at: 0)

現在運行後會得到下面的結果:

顏色漸變是做到瞭,那麼如何做到顏色漸變的轉換呢?這裡還是需要用到CABasicAnimation.
在gradient創建完之後,添加並調用一個方法animateGradient,在裡面添加一個keyPath為colors的CABasicAnimation,設置動畫時長為3s,設置結束值等一系列屬性。

func animateGradient() {
  let gradientChangeAnimation = CABasicAnimation(keyPath: "colors")
        gradientChangeAnimation.duration = 3.0
        gradientChangeAnimation.toValue =  [colorTwo,colorThree]
        gradientChangeAnimation.fillMode = CAMediaTimingFillMode.forwards
        gradientChangeAnimation.isRemovedOnCompletion = false
        gradient.add(gradientChangeAnimation, forKey: "gradientChangeAnimation")
      }

這裡就完成瞭轉換動畫。但是這裡有個問題就是這裡隻轉換瞭一次,無法轉換多次顏色。那麼這裡就需要設置好toValue,讓每次的toValue都不一樣。
創建一個currentGradient和gradientSet讓VC持有。

var currentGradient: Int = 0
var gradientSet = [[CGColor]]()

在animateGradient中每次調用的時候,都對currentGradient的值進行判斷和處理。

if currentGradient < gradientSet.count - 1 {
            currentGradient += 1
        } else {
            currentGradient = 0
        }

並修改gradientChangeAnimation的toValue:

let gradientChangeAnimation = CABasicAnimation(keyPath: "colors")
gradientChangeAnimation.duration = 3.0
gradientChangeAnimation.toValue = gradientSet[currentGradient]
gradientChangeAnimation.fillMode = CAMediaTimingFillMode.forwards
gradientChangeAnimation.isRemovedOnCompletion = false
gradientChangeAnimation.repeatCount = Float.infinity
gradient.add(gradientChangeAnimation, forKey: "gradientChangeAnimation")

這裡運行後發現還是不行,還是隻有一種顏色的轉換,這是因為這裡隻調用瞭一次animateGradient()。那麼如何在合適的時機,也就是動畫結束的時候再調用一次animateGradient呢?這裡就需要用到CAAnimationDelegate。
在CAAnimationDelegate的animationDidStop方法中重新調用animateGradient。註意這裡的gradient.colors 也要改變,否則就會一直是[colorOne, colorTwo]到其他顏色的變換。

func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
        
        // if our gradient animation ended animating, restart the animation by changing the color set
        if flag {
            gradient.colors = gradientSet[currentGradient]
            animateGradient()
        }
    }

完整代碼:

import UIKit

class ViewController: UIViewController, CAAnimationDelegate {
    let colorOne = #colorLiteral(red: 0.2392156869, green: 0.6745098233, blue: 0.9686274529, alpha: 1).cgColor
    let colorTwo = #colorLiteral(red: 0.8078431487, green: 0.02745098062, blue: 0.3333333433, alpha: 1).cgColor
    let colorThree = #colorLiteral(red: 0.9607843161, green: 0.7058823705, blue: 0.200000003, alpha: 1).cgColor
    let gradient = CAGradientLayer()
    
    var currentGradient: Int = 0
    var gradientSet = [[CGColor]]()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        NotificationCenter.default.addObserver(self, selector: #selector(handleEnterForeground), name: UIApplication.willEnterForegroundNotification, object: nil)
        
    }
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        
        createGradientView()
    }
    
    @objc private func handleEnterForeground() {
        animateGradient()
    }
    
    func animateGradient() {
        // cycle through all the colors, feel free to add more to the set
        if currentGradient < gradientSet.count - 1 {
            currentGradient += 1
        } else {
            currentGradient = 0
        }
        
        // animate over 3 seconds
        let gradientChangeAnimation = CABasicAnimation(keyPath: "colors")
        gradientChangeAnimation.duration = 3.0
        gradientChangeAnimation.toValue = gradientSet[currentGradient]
        gradientChangeAnimation.fillMode = CAMediaTimingFillMode.forwards
        gradientChangeAnimation.isRemovedOnCompletion = false
        //gradientChangeAnimation.repeatCount = Float.infinity
        gradientChangeAnimation.delegate = self
        gradient.add(gradientChangeAnimation, forKey: "gradientChangeAnimation")
    }
    
    func createGradientView() {
        
        // overlap the colors and make it 3 sets of colors
        gradientSet.append([colorOne, colorTwo])
        gradientSet.append([colorTwo, colorThree])
        gradientSet.append([colorThree, colorOne])
        
        // set the gradient size to be the entire screen
        gradient.frame = self.view.bounds
        gradient.colors = gradientSet[currentGradient]
        gradient.startPoint = CGPoint(x:0, y:0)
        gradient.endPoint = CGPoint(x:1, y:1)
        gradient.drawsAsynchronously = true
        
        self.view.layer.insertSublayer(gradient, at: 0)
        
        animateGradient()
    }
    func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
        
        // if our gradient animation ended animating, restart the animation by changing the color set
        if flag {
            gradient.colors = gradientSet[currentGradient]
            animateGradient()
        }
    }
    
}

以上就是本文的全部內容,希望對大傢的學習有所幫助,也希望大傢多多支持WalkonNet。

推薦閱讀: