本文是通过结合使用CAGradientLayer、CABasicAnimation以及CAAnimationDelegate来达到颜色渐变以及转换的动画,下面是今天要达成的效果图:
首先创建一个CAGradientLayer和几个自己喜欢的颜色,让VC持有。
1
2
3
4
|
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中。
1
2
3
4
5
6
|
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,设置结束值等一系列属性。
1
2
3
4
5
6
7
8
|
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持有。
1
2
|
var currentGradient: Int = 0 var gradientSet = [[CGColor]]() |
在animateGradient中每次调用的时候,都对currentGradient的值进行判断和处理。
1
2
3
4
5
|
if currentGradient < gradientSet.count - 1 { currentGradient += 1 } else { currentGradient = 0 } |
并修改gradientChangeAnimation的toValue:
1
2
3
4
5
6
7
|
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]到其他颜色的变换。
1
2
3
4
5
6
7
8
|
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() } } |
完整代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
|
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() } } } |
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:https://blog.csdn.net/LinShunIos/article/details/120669939