2017-02-25 105 views
1

我有一個圖如下圖所示:如何用漸變動畫陰影?

enter image description here

我有動畫和陰影的問題。 我使用動畫繪製漸變,但是從一開始我就有了我不想要的陰影和遮罩層,我希望陰影使用漸變動畫。 帶動畫的當前圖表如下所示。 enter image description here

我不希望用戶從頭看到陰影和遮罩層。

這裏是我的代碼:

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

您應該創建另一個圖層以提供陰影。

1 - 首先你要創建一個UIView作爲shadowLayer

2 - 然後屏蔽此shadowLayer與路徑和層相同maskLayer(在你的代碼)已創建。例如:shadowMaskLayer

3 - 陰影屬性添加到這個新的shadowMaskLayer

4 - 然後添加shadowLayer到原來的UIView CircularProgressView

5 - 還可以添加你已經有這個shadowLayer動畫動畫整個圓圈的陰影。

不要猶豫發問;)

+1

謝謝,這是一個好主意。我會改變我的代碼並分享結果。 – Mina

1

好了,我在這裏把正確的答案,也許有人需要它的未來。

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 
} 
} 

此溶液繪製動畫梯度和陰影的弧。 您可以在我的Github中找到完整的項目。