Swift 如何使用渐变设置阴影动画?

Swift 如何使用渐变设置阴影动画?,swift,animation,gradient,shadow,Swift,Animation,Gradient,Shadow,我有如下图表: 我对动画和阴影有问题。 我用动画绘制渐变,但从一开始我就有阴影和遮罩层,我不想要,我想要阴影用渐变设置动画。 当前带有动画的图表如下所示。 我不希望用户从一开始就看到阴影和遮罩层 这是我的密码: import Foundation import UIKit @IBDesignable class CircularProgressView: UIView { @IBInspectable var containerCircleColor: UIColor = UIColor

我有如下图表:

我对动画和阴影有问题。 我用动画绘制渐变,但从一开始我就有阴影和遮罩层,我不想要,我想要阴影用渐变设置动画。 当前带有动画的图表如下所示。

我不希望用户从一开始就看到阴影和遮罩层

这是我的密码:

import Foundation
import UIKit

@IBDesignable class CircularProgressView: UIView {

@IBInspectable var containerCircleColor: UIColor = UIColor.lightGray
@IBInspectable var gradientStartColor: UIColor = UIColor.green
@IBInspectable var gradientEndColor: UIColor = UIColor.yellow
@IBInspectable var arcWidth: CGFloat = 20


override init(frame: CGRect) {
    super.init(frame: frame)
    circularProgressView_init()
}

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    circularProgressView_init()
}


fileprivate func circularProgressView_init() {

    let viewHeight = NSLayoutConstraint(item: self, attribute: .height, relatedBy: .equal, toItem: self, attribute: .width, multiplier: 1, constant: 0)
    self.addConstraint(viewHeight)

}

override func prepareForInterfaceBuilder() {
    circularProgressView_init()
}

override func draw(_ rect: CGRect) {
    let width = self.bounds.width
    let center = CGPoint(x: self.bounds.midX, y: self.bounds.midY)
    let radius: CGFloat = (width - (arcWidth * 2.5)) / 2
    let progressStartAngle: CGFloat = 3 * CGFloat.pi / 2
    let progressEndAngle: CGFloat = CGFloat.pi / 2

    //fill circular
    let circlePath = UIBezierPath(arcCenter:  center,
                                  radius: radius,
                                  startAngle: 0,
                                  endAngle: 360,
                                  clockwise: true)
    circlePath.lineWidth = arcWidth
    containerCircleColor.setStroke()
    circlePath.stroke()


    //MARK: ProgressPath
    let progressPath = UIBezierPath(arcCenter: center,
                                    radius: radius,
                                    startAngle: progressStartAngle,
                                    endAngle: progressEndAngle,
                                    clockwise: true)
    progressPath.lineWidth = arcWidth
    progressPath.lineCapStyle = .round

    //MARK: Gradient
    let gradientLayer = CAGradientLayer()
    gradientLayer.colors = [gradientStartColor.cgColor , gradientEndColor.cgColor]
    gradientLayer.startPoint = CGPoint(x: 0, y: 0)
    gradientLayer.endPoint = CGPoint(x:1, y:1)
    gradientLayer.frame = self.bounds

    //MARK: Animation
    let anim = CABasicAnimation(keyPath: "strokeEnd")
    anim.duration = 2
    anim.fillMode = kCAFillModeForwards
    anim.fromValue = 0
    anim.toValue = 1

    //MARK: Mask Layer
    let maskLayer = CAShapeLayer()
    maskLayer.path = progressPath.cgPath
    maskLayer.fillColor = UIColor.clear.cgColor
    maskLayer.strokeColor = UIColor.black.cgColor
    maskLayer.lineWidth = arcWidth
    maskLayer.lineCap = kCALineCapRound

    gradientLayer.mask = maskLayer

    self.layer.insertSublayer(gradientLayer, at: 0)

    let context = UIGraphicsGetCurrentContext()
    let shadow = UIColor.lightGray
    let shadowOffset = CGSize(width: 3.1, height: 3.1)
    let shadowBlurRadius: CGFloat = 5
    context!.saveGState()
    context!.setShadow(offset: shadowOffset, blur: shadowBlurRadius,  color: (shadow as UIColor).cgColor)
    progressPath.stroke()
    context?.restoreGState()

    maskLayer.add(anim, forKey: nil)
    gradientLayer.add(anim, forKey: nil)

  }
}
有可能吗?
如果不是,我如何至少隐藏阴影和遮罩,并在动画结束后显示它?

您应该创建另一层以提供阴影

1-首先,您必须创建一个UIView作为
阴影层

2-然后使用与您已经创建的
maskLayer
(在您的代码中)相同的路径和层遮罩此
阴影层。e、 g:
shadowMaskLayer

3-将阴影属性添加到此新的
shadowMaskLayer

4-然后将
shadowLayer
添加到原始UIView
CircularProgressView

5-还将您已经拥有的动画添加到此
阴影层
,以使用整个圆设置阴影动画


不要犹豫问问题;)

好吧,我把正确答案放在这里,也许将来会有人需要它

import Foundation
import UIKit

@IBDesignable class CircularProgressView: UIView {

@IBInspectable var containerCircleColor: UIColor = UIColor.lightGray
@IBInspectable var gradientStartColor: UIColor = UIColor.yellow
@IBInspectable var gradientEndColor: UIColor = UIColor.red
@IBInspectable var arcWidth: CGFloat = 20
@IBInspectable var progressPercent: CGFloat = 50

override init(frame: CGRect) {
    super.init(frame: frame)
    circularProgressView_init()
}

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    circularProgressView_init()
}

fileprivate func circularProgressView_init() {
    let viewHeight = NSLayoutConstraint(item: self, attribute: .height, relatedBy: .equal, toItem: self, attribute: .width, multiplier: 1, constant: 0)
    self.addConstraint(viewHeight)
}

override func prepareForInterfaceBuilder() {
    circularProgressView_init()
}

override func draw(_ rect: CGRect) {
    let width = self.bounds.width
    let center = CGPoint(x: self.bounds.midX, y: self.bounds.midY)
    let radius: CGFloat = (width - (arcWidth * 2.5)) / 2
    let progressStartAngle: CGFloat = 3 * CGFloat.pi / 2
    let progressEndAngle: CGFloat = ConvertToTrigonometry.shared.trigonimetryCordinate(percentage: progressPercent) //CGFloat.pi / 2

    //fill circular
    let circlePath = UIBezierPath(arcCenter:  center,
                                  radius: radius,
                                  startAngle: 0,
                                  endAngle: 360,
                                  clockwise: true)
    circlePath.lineWidth = arcWidth
    containerCircleColor.setStroke()
    circlePath.stroke()


    //MARK: ProgressPath
    let progressPath = UIBezierPath(arcCenter: center,
                                    radius: radius,
                                    startAngle: progressStartAngle,
                                    endAngle: progressEndAngle,
                                    clockwise: true)
    progressPath.lineWidth = arcWidth
    progressPath.lineCapStyle = .round

    //MARK: Gradient
    let gradientLayer = CAGradientLayer()
    gradientLayer.colors = [gradientStartColor.cgColor , gradientEndColor.cgColor]
    gradientLayer.startPoint = CGPoint(x: 0, y: 0)
    gradientLayer.endPoint = CGPoint(x:1, y:1)
    gradientLayer.frame = self.bounds

    //MARK: Mask Layer
    let maskLayer = CAShapeLayer()
    maskLayer.path = progressPath.cgPath
    maskLayer.fillColor = UIColor.clear.cgColor
    maskLayer.backgroundColor = UIColor.black.cgColor
    maskLayer.strokeColor = UIColor.black.cgColor
    maskLayer.lineWidth = arcWidth
    maskLayer.lineCap = kCALineCapRound
    maskLayer.masksToBounds = false

    gradientLayer.mask = maskLayer

    //MARK: Shadow
    let shadowLayer = CAShapeLayer()
    shadowLayer.frame = bounds
    shadowLayer.backgroundColor = UIColor.gray.cgColor
    layer.addSublayer(shadowLayer)

    let maskShadowLayer = CAShapeLayer()
    maskShadowLayer.path = progressPath.cgPath
    maskShadowLayer.fillColor = UIColor.clear.cgColor
    maskShadowLayer.backgroundColor = UIColor.black.cgColor
    maskShadowLayer.strokeColor = UIColor.black.cgColor
    maskShadowLayer.lineWidth = arcWidth
    maskShadowLayer.lineCap = kCALineCapRound
    maskShadowLayer.masksToBounds = false
    maskShadowLayer.shadowColor = UIColor.black.cgColor
    maskShadowLayer.shadowOpacity = 0.5
    maskShadowLayer.shadowOffset = CGSize(width: 3.1, height: 3.1)

    shadowLayer.mask = maskShadowLayer

    //MARK: Animation
    let anim = CABasicAnimation(keyPath: "strokeEnd")
    anim.duration = 2
    anim.fillMode = kCAFillModeForwards
    anim.fromValue = 0
    anim.toValue = 1

    maskShadowLayer.add(anim, forKey: nil)
    maskLayer.add(anim, forKey: nil)
    gradientLayer.add(anim, forKey: nil)

    layer.addSublayer(gradientLayer)

 }

}
还有一个辅助类,用于三角转换:

import Foundation
import UIKit

class ConvertToTrigonometry {

static let shared = ConvertToTrigonometry()

func trigonimetryCordinate(percentage: CGFloat) -> CGFloat {
    let pi = CGFloat.pi
    let trigonometryRatio = (percentage * 360) / 100 // How much you want to move forward in axis.
    let endPointDegree = (3 * pi / 2) + ((trigonometryRatio * 2 / 360) * pi) // End point on axis based on your trigonometryRatio and the start point which is 3pi/2
    return endPointDegree
 }
}
此解决方案使用动画渐变和阴影绘制圆弧。
您可以在我的中找到完整的项目。

谢谢,这是个好主意。我将更改代码并共享结果。