添加从一个视图流向另一个视图的微光动画
Add shimmer animation flowing from one view to another
我正在尝试创建从一个视图流向另一个视图的微光动画。以下是我到目前为止的代码:
override func viewDidLoad() {
super.viewDidLoad()
view1.backgroundColor = .purple
view2.backgroundColor = .purple
view1.startAnimating()
//let seconds = 2.0
//DispatchQueue.main.asyncAfter(deadline: .now() + seconds) {
self.view2.startAnimating()
//}
}
class ShimmerView: UIView {
let gradientColorOne : CGColor = UIColor.purple.cgColor
let gradientColorTwo : CGColor = UIColor.yellow.cgColor
func addGradientLayer() -> CAGradientLayer {
let gradientLayer = CAGradientLayer()
gradientLayer.frame = self.bounds
gradientLayer.startPoint = CGPoint(x: 0.0, y: 0.0)
gradientLayer.endPoint = CGPoint(x: 0.0, y: 1.0)
gradientLayer.colors = [gradientColorOne, gradientColorTwo, gradientColorOne]
gradientLayer.locations = [0.0, 0.5, 1.0]
self.layer.addSublayer(gradientLayer)
return gradientLayer
}
func addAnimation() -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: "locations")
animation.fromValue = [-1.0, -0.5, 0.0]
animation.toValue = [1.0, 1.5, 2.0]
animation.repeatCount = .infinity
animation.duration = 2
return animation
}
func startAnimating() {
let gradientLayer = addGradientLayer()
let animation = addAnimation()
gradientLayer.add(animation, forKey: animation.keyPath)
}
}
我尝试添加延迟,但我想这不会奏效,因为下次动画应该以进一步延迟开始。
这就是它现在的行为方式。动画并行发生:
但是,我想要的是它从 view1 开始动画,然后在 view2 中结束,然后继续这样做。关于如何实现这一目标的任何想法/建议?谢谢。
您可以尝试从调用站点控制动画顺序,如下所示。
- 像这样在
ShimmerView
中定义一个名为 animationDuration
的常量。
public static let animationDuration: Double = 2.0
- 像这样更新
addAnimation()
实现。
// Remove this line, We need this to be performed only once at a time.
/*
animation.repeatCount = .infinity
*/
// Update this line to use the constant defined earlier
animation.duration = ShimmerView.animationDuration
- 从您的调用站点,您现在可以执行此操作。
class ViewController: UIViewController {
let view1 = ShimmerView()
let view2 = ShimmerView()
func startAnimating() {
view1.startAnimating()
let interval = ShimmerView.animationDuration
DispatchQueue.main.asyncAfter(deadline: .now() + interval) { [weak self] in
self?.view2.startAnimating()
DispatchQueue.main.asyncAfter(deadline: .now() + interval) { [weak self] in
self?.startAnimating()
}
}
}
}
更新
This kind of almost works, but when view1 finishes the animation and view2 starts it, the gradient on view1 sits in the middle and vice versa. So, it doesn't give a clear flowing animation from top to bottom that goes on.
问题是您的代码没有在动画完成后从您的视图中移除 gradientLayer 实例。您可以使用 CATransaction.setCompletionBlock
来完成,如下所示。
import Foundation
import UIKit
class ShimmerView: UIView {
static let animationDuration: Double = 2.0
let gradientColorOne: CGColor = UIColor.purple.cgColor
let gradientColorTwo: CGColor = UIColor.yellow.cgColor
lazy var gradientLayer: CAGradientLayer = {
let gradient = CAGradientLayer()
gradient.startPoint = CGPoint(x: 0.0, y: 0.0)
gradient.endPoint = CGPoint(x: 0.0, y: 1.0)
gradient.colors = [gradientColorOne, gradientColorTwo, gradientColorOne]
gradient.locations = [0.0, 0.5, 1.0]
return gradient
}()
func addGradientLayer() {
gradientLayer.frame = self.bounds
self.layer.addSublayer(gradientLayer)
}
func removeGradientLayer() {
gradientLayer.removeFromSuperlayer()
}
func addAnimation() -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: "locations")
animation.fromValue = [-1.0, -0.5, 0.0]
animation.toValue = [1.0, 1.5, 2.0]
animation.duration = ShimmerView.animationDuration
return animation
}
func startAnimating() {
self.addGradientLayer()
let animation = addAnimation()
CATransaction.begin()
// Setting this block before adding the animation is crucial
CATransaction.setCompletionBlock({ [weak self] in
self?.removeGradientLayer()
})
gradientLayer.add(animation, forKey: animation.keyPath)
CATransaction.commit()
}
}
我正在尝试创建从一个视图流向另一个视图的微光动画。以下是我到目前为止的代码:
override func viewDidLoad() {
super.viewDidLoad()
view1.backgroundColor = .purple
view2.backgroundColor = .purple
view1.startAnimating()
//let seconds = 2.0
//DispatchQueue.main.asyncAfter(deadline: .now() + seconds) {
self.view2.startAnimating()
//}
}
class ShimmerView: UIView {
let gradientColorOne : CGColor = UIColor.purple.cgColor
let gradientColorTwo : CGColor = UIColor.yellow.cgColor
func addGradientLayer() -> CAGradientLayer {
let gradientLayer = CAGradientLayer()
gradientLayer.frame = self.bounds
gradientLayer.startPoint = CGPoint(x: 0.0, y: 0.0)
gradientLayer.endPoint = CGPoint(x: 0.0, y: 1.0)
gradientLayer.colors = [gradientColorOne, gradientColorTwo, gradientColorOne]
gradientLayer.locations = [0.0, 0.5, 1.0]
self.layer.addSublayer(gradientLayer)
return gradientLayer
}
func addAnimation() -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: "locations")
animation.fromValue = [-1.0, -0.5, 0.0]
animation.toValue = [1.0, 1.5, 2.0]
animation.repeatCount = .infinity
animation.duration = 2
return animation
}
func startAnimating() {
let gradientLayer = addGradientLayer()
let animation = addAnimation()
gradientLayer.add(animation, forKey: animation.keyPath)
}
}
我尝试添加延迟,但我想这不会奏效,因为下次动画应该以进一步延迟开始。
这就是它现在的行为方式。动画并行发生:
但是,我想要的是它从 view1 开始动画,然后在 view2 中结束,然后继续这样做。关于如何实现这一目标的任何想法/建议?谢谢。
您可以尝试从调用站点控制动画顺序,如下所示。
- 像这样在
ShimmerView
中定义一个名为animationDuration
的常量。
public static let animationDuration: Double = 2.0
- 像这样更新
addAnimation()
实现。
// Remove this line, We need this to be performed only once at a time.
/*
animation.repeatCount = .infinity
*/
// Update this line to use the constant defined earlier
animation.duration = ShimmerView.animationDuration
- 从您的调用站点,您现在可以执行此操作。
class ViewController: UIViewController {
let view1 = ShimmerView()
let view2 = ShimmerView()
func startAnimating() {
view1.startAnimating()
let interval = ShimmerView.animationDuration
DispatchQueue.main.asyncAfter(deadline: .now() + interval) { [weak self] in
self?.view2.startAnimating()
DispatchQueue.main.asyncAfter(deadline: .now() + interval) { [weak self] in
self?.startAnimating()
}
}
}
}
更新
This kind of almost works, but when view1 finishes the animation and view2 starts it, the gradient on view1 sits in the middle and vice versa. So, it doesn't give a clear flowing animation from top to bottom that goes on.
问题是您的代码没有在动画完成后从您的视图中移除 gradientLayer 实例。您可以使用 CATransaction.setCompletionBlock
来完成,如下所示。
import Foundation
import UIKit
class ShimmerView: UIView {
static let animationDuration: Double = 2.0
let gradientColorOne: CGColor = UIColor.purple.cgColor
let gradientColorTwo: CGColor = UIColor.yellow.cgColor
lazy var gradientLayer: CAGradientLayer = {
let gradient = CAGradientLayer()
gradient.startPoint = CGPoint(x: 0.0, y: 0.0)
gradient.endPoint = CGPoint(x: 0.0, y: 1.0)
gradient.colors = [gradientColorOne, gradientColorTwo, gradientColorOne]
gradient.locations = [0.0, 0.5, 1.0]
return gradient
}()
func addGradientLayer() {
gradientLayer.frame = self.bounds
self.layer.addSublayer(gradientLayer)
}
func removeGradientLayer() {
gradientLayer.removeFromSuperlayer()
}
func addAnimation() -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: "locations")
animation.fromValue = [-1.0, -0.5, 0.0]
animation.toValue = [1.0, 1.5, 2.0]
animation.duration = ShimmerView.animationDuration
return animation
}
func startAnimating() {
self.addGradientLayer()
let animation = addAnimation()
CATransaction.begin()
// Setting this block before adding the animation is crucial
CATransaction.setCompletionBlock({ [weak self] in
self?.removeGradientLayer()
})
gradientLayer.add(animation, forKey: animation.keyPath)
CATransaction.commit()
}
}