You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS锥形边框渐变动画异常:闪烁问题求解决方案

多色锥形渐变边框动画闪烁问题修复方案

问题根源

闪烁问题主要源于三点:

  • Timer触发动画与Core Animation周期不同步,导致衔接断层
  • 仅动画colors属性未同步动画locations,多色渐变下位置不匹配引发闪烁
  • 频繁在CATransaction完成块中移除、添加动画,造成图层状态切换的视觉跳变

修复代码

class ViewController: UIViewController {
    private enum Color {
        static var gradientColors: [UIColor] = [
            .white,
            .systemBlue,
            .systemPink,
            .systemGreen,
            UIColor(white: 1, alpha: 0)
        ]
    }

    @IBOutlet weak var gradientView: UIView! {
        didSet {
            gradientView.layer.cornerRadius = 16
        }
    }

    private var gradientLayer: CAGradientLayer!

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        setupAnimatedBorder()
    }

    private func setupAnimatedBorder() {
        // 创建遮罩形状层
        let shapeLayer = CAShapeLayer()
        shapeLayer.path = UIBezierPath(
            roundedRect: gradientView.bounds.insetBy(dx: 1.0, dy: 1.0),
            cornerRadius: gradientView.layer.cornerRadius
        ).cgPath
        shapeLayer.lineWidth = 1.0
        shapeLayer.strokeColor = UIColor.white.cgColor
        shapeLayer.fillColor = UIColor.clear.cgColor

        // 初始化锥形渐变层
        gradientLayer = CAGradientLayer()
        gradientLayer.frame = gradientView.bounds
        gradientLayer.type = .conic
        gradientLayer.startPoint = CGPoint(x: 0.5, y: 0.5)
        gradientLayer.endPoint = CGPoint(x: 1, y: 1)
        gradientLayer.mask = shapeLayer
        gradientView.layer.addSublayer(gradientLayer)

        // 启动循环动画
        startGradientAnimation()
    }

    private func startGradientAnimation() {
        let colorCount = Color.gradientColors.count
        
        // 生成对应偏移量的位置数组
        func locations(forOffset offset: Int) -> [NSNumber] {
            let baseValues = stride(from: 0, to: colorCount, by: 1).map {
                Double($0) + Double(offset)
            }
            return baseValues.map { NSNumber(value: fmod($0, Double(colorCount)) / Double(colorCount)) }
        }

        // 生成颜色滚动的关键帧
        let colorKeyframes = (0...colorCount).map { index in
            let shiftedColors = Array(Color.gradientColors[index...] + Color.gradientColors[..<index])
            return shiftedColors.map { $0.cgColor }
        }
        let colorAnimation = CAKeyframeAnimation(keyPath: "colors")
        colorAnimation.values = colorKeyframes
        colorAnimation.duration = 2.0
        colorAnimation.repeatCount = .infinity
        colorAnimation.isRemovedOnCompletion = false

        // 生成位置同步的关键帧
        let locationKeyframes = (0...colorCount).map { locations(forOffset: $0) }
        let locationAnimation = CAKeyframeAnimation(keyPath: "locations")
        locationAnimation.values = locationKeyframes
        locationAnimation.duration = 2.0
        locationAnimation.repeatCount = .infinity
        locationAnimation.isRemovedOnCompletion = false

        // 组合动画确保同步
        let animationGroup = CAAnimationGroup()
        animationGroup.animations = [colorAnimation, locationAnimation]
        animationGroup.duration = 2.0
        animationGroup.repeatCount = .infinity
        animationGroup.timingFunction = CAMediaTimingFunction(name: .linear)

        // 设置初始状态并添加动画
        gradientLayer.colors = Color.gradientColors.map { $0.cgColor }
        gradientLayer.locations = locations(forOffset: 0)
        gradientLayer.add(animationGroup, forKey: "gradientScroll")
    }

    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        // 页面消失时清理动画
        gradientLayer?.removeAllAnimations()
    }
}

核心改动说明

  1. 替换Timer为原生动画循环:利用Core Animation的repeatCount = .infinity实现无限循环,避免定时器与动画引擎的同步问题
  2. 同步动画colors与locations:多色渐变中颜色位置必须随颜色数组同步偏移,否则会出现颜色断层闪烁
  3. 关键帧动画实现平滑滚动:预先生成所有颜色偏移的关键帧,让颜色过渡无断层
  4. 简化图层结构:仅保留一个渐变层,减少图层数量降低性能消耗
  5. 添加动画清理逻辑:避免视图销毁后残留动画导致的内存泄漏

内容的提问来源于stack exchange,提问作者Novice

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 14:30:55