我的以下代码显示了该问题:
import UIKit
import SnapKit
class ViewController: UIViewController {
let animatedBorderView = AnimatedGradientBorderView()
override func viewDidLoad() {
super.viewDidLoad()
animatedBorderView.layer.cornerRadius = 20
animatedBorderView.clipsToBounds = true
view.addSubview(animatedBorderView)
animatedBorderView.snp.makeConstraints { make in
make.center.equalToSuperview()
make.size.equalTo(400)
}
}
}
class AnimatedGradientBorderView: UIView {
private let gradientLayer = CAGradientLayer()
private let shapeLayer = CAShapeLayer()
override init(frame: CGRect) {
super.init(frame: frame)
setupLayers()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setupLayers()
}
private func setupLayers() {
gradientLayer.startPoint = CGPoint(x: 0, y: 0)
gradientLayer.endPoint = CGPoint(x: 1, y: 1)
gradientLayer.colors = [
UIColor.systemRed.cgColor,
UIColor.systemYellow.cgColor,
UIColor.systemGreen.cgColor,
]
gradientLayer.locations = [0, 0.3, 0.6, 1]
layer.addSublayer(gradientLayer)
shapeLayer.lineWidth = 5
shapeLayer.fillColor = nil
shapeLayer.strokeColor = UIColor.black.cgColor
gradientLayer.mask = shapeLayer
startAnimating()
}
override func layoutSubviews() {
super.layoutSubviews()
gradientLayer.frame = bounds
let path = UIBezierPath(roundedRect: bounds.insetBy(dx: shapeLayer.lineWidth / 2, dy: shapeLayer.lineWidth / 2), cornerRadius: layer.cornerRadius)
shapeLayer.path = path.cgPath
}
private func startAnimating() {
let animation = CABasicAnimation(keyPath: "locations")
animation.fromValue = [0, 0.2, 0.4, 0.6]
animation.toValue = [0.4, 0.6, 0.8, 1]
animation.duration = 2.0
animation.repeatCount = .infinity
animation.autoreverses = false
gradientLayer.add(animation, forKey: "animateLocations")
}
}
这将产生以下动画:
请注意,我将其设置autoreverses
为 false,因为我不想让它在重复到 时反转回来infinity
。然而,这样做的结果是,在 之后duration
,它会从原来的 重新开始location
。这会导致移动渐变边框突然跳动。
我怎样才能让它一直朝一个方向移动而不重置?
为了实现旋转边框效果,我改用了圆锥渐变 (.conic),它会自然地围绕中心点辐射颜色。我不再手动移动颜色,而是让整个渐变图层绕 z 轴旋转。(参考iOS 中类似蛇形渐变的边框动画)
尝试一下: