2017-02-25 4 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 - その後、パスとすでに作成している(あなたのコード内)maskLayerと同じ層で、このshadowLayerをマスク - 最初のあなたはshadowLayer

2としてのUIViewを作成する必要があります。例えば:shadowMaskLayer

3 - この新しいshadowMaskLayer

4に影のプロパティを追加します - 元のUIViewにCircularProgressView

5をshadowLayerを追加する - また、アニメーション化するために、この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で完全なプロジェクトを見つけることができます。

関連する問題