web-dev-qa-db-ja.com

UIBezierPathで作成された円弧にグラデーションカラーを適用します

円弧の形をしたプログレスバーを作成したいと思います。プログレスバーの色は、値に応じて変更する必要があります。

UIBezierPath bezierPathWithArcCenterを使用して円弧を作成しました。次のコードを使用しました。

- (void)viewDidLoad
{
    [super viewDidLoad];

    int radius = 100;

    CAShapeLayer *arc = [CAShapeLayer layer];

    arc.path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(100, 50) radius:radius startAngle:60.0 endAngle:0.0 clockwise:YES].CGPath;

    arc.position = CGPointMake(CGRectGetMidX(self.view.frame)-radius,
                                  CGRectGetMidY(self.view.frame)-radius);

    arc.fillColor = [UIColor clearColor].CGColor;
    arc.strokeColor = [UIColor purpleColor].CGColor;
    arc.lineWidth = 15;

    [self.view.layer addSublayer:arc];

    CABasicAnimation *drawAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
    drawAnimation.duration            = 5.0; // "animate over 10 seconds or so.."
    drawAnimation.repeatCount         = 1.0;  // Animate only once..
    drawAnimation.removedOnCompletion = NO;   // Remain stroked after the animation..
    drawAnimation.fromValue = [NSNumber numberWithFloat:0.0f];
    drawAnimation.toValue   = [NSNumber numberWithFloat:10.0f];
    drawAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
    [arc addAnimation:drawAnimation forKey:@"drawCircleAnimation"];

}

結果は次のようになります。

enter image description here

私の質問は:値が<= 50%の場合、色にグラデーションを適用するにはどうすればよいですか?また、プログレスバーに接続するためにランダムなCGFloat番号を生成するUIButtonを作成しました。誰かがこれに取り組む方法を知っていますか?

グラデーションは次のようになります。

enter image description here

どんな助けでもいただければ幸いです!

どうもありがとうございました。

花崗岩

26
Granit

CAGradientLayerを使用してグラデーション効果を取得し、CAShapeLayerをマスクとして使用できます。

例えば。:

- (void)viewDidLoad
{
    [super viewDidLoad];

    int radius = 100;

    CAShapeLayer *arc = [CAShapeLayer layer];    
    arc.path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(100, 50) radius:radius startAngle:60.0 endAngle:0.0 clockwise:YES].CGPath;

    arc.position = CGPointMake(CGRectGetMidX(self.view.frame)-radius,
                               CGRectGetMidY(self.view.frame)-radius);

    arc.fillColor = [UIColor clearColor].CGColor;
    arc.strokeColor = [UIColor purpleColor].CGColor;
    arc.lineWidth = 15; 
    CABasicAnimation *drawAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
    drawAnimation.duration            = 5.0; // "animate over 10 seconds or so.."
    drawAnimation.repeatCount         = 1.0;  // Animate only once..
    drawAnimation.removedOnCompletion = NO;   // Remain stroked after the animation..
    drawAnimation.fromValue = [NSNumber numberWithFloat:0.0f];
    drawAnimation.toValue   = [NSNumber numberWithFloat:10.0f];
    drawAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
    [arc addAnimation:drawAnimation forKey:@"drawCircleAnimation"];

    CAGradientLayer *gradientLayer = [CAGradientLayer layer];
    gradientLayer.frame = self.view.frame;
    gradientLayer.colors = @[(__bridge id)[UIColor redColor].CGColor,(__bridge id)[UIColor blueColor].CGColor ];
    gradientLayer.startPoint = CGPointMake(0,0.5);
    gradientLayer.endPoint = CGPointMake(1,0.5);

    [self.view.layer addSublayer:gradientLayer];
     //Using arc as a mask instead of adding it as a sublayer.
     //[self.view.layer addSublayer:arc]; 
     gradientLayer.mask = arc;


}
38
djshiow

enter image description here

ストロークに沿ってグラデーションを描画するには、次の実装を参照してください: https://stackoverflow.com/a/43668420/917802

編集:要するに、カスタムUIViewクラスを作成し、角度を増やして2つの色の間を反復することにより、それに放射状のグラデーションを追加します。 colour1 = 1度、colour2 = 2度など、360度まで。次にドーナツマスクを適用します。マスキングCAShapeLayerのstrokeEnd値を変更すると、基になる放射状グラデーションも回転します。それらが一緒に移動するため、ストローク自体にグラデーションがあるように見えます。

1
Johnny Rockex

これまでの回答は素晴らしいですが、少し複雑なので、次のロジックはもっと単純なはずだと思います。

  1. シェイプレイヤーのカーブ/パスを描画します。
  2. パス自体を閉じます。つまり、同じカーブ/パスを逆に描画します。
  3. CAShapeLayerを作成し、そのパスを(2)のパスに設定します。
  4. (3)のシェイプレイヤーに任意のストロークカラーを与えます。
  5. CAGradientLayerを作成します。
  6. (4)のシェイプレイヤーにグラデーションレイヤーマスクを設定します。
  7. グラデーションレイヤーの色を目的の配列に設定します。
  8. (1)で元のshapeLayerにグラデーションレイヤーを追加します。
func draweCurve(fromPoint: CGPoint, toPoint: CGPoint, x: CGFloat) {
    // ------- 1 --------
    let curveLayer = CAShapeLayer()
    curveLayer.contentsScale = UIScreen.main.scale
    curveLayer.frame = CGRect(Origin: .zero, size: CGSize(width: 100, height: 100))
    curveLayer.fillColor = UIColor.red.cgColor
    curveLayer.strokeColor = UIColor.blue.cgColor

    let path = UIBezierPath()
    path.move(to: fromPoint)
    let controlPoint1 = CGPoint(x: fromPoint.x + 40 * 0.45, y: fromPoint.y)
    let controlPoint2 = CGPoint(x: toPoint.x - 40 * 0.45, y: toPoint.y)
    path.addCurve(to: toPoint, controlPoint1: controlPoint1, controlPoint2: controlPoint2)
    curveLayer.path = path.cgPath

    // ------- 2 --------
    // close the path on its self
    path.addCurve(to: fromPoint, controlPoint1: controlPoint2, controlPoint2: controlPoint1)
    addGradientLayer(to: curveLayer, path: path)
}

private func addGradientLayer(to layer: CALayer, path: UIBezierPath) {
    // ------- 3 --------
    let gradientMask = CAShapeLayer()
    gradientMask.contentsScale = UIScreen.main.scale
    // ------- 4 --------
    gradientMask.strokeColor = UIColor.white.cgColor
    gradientMask.path = path.cgPath

    // ------- 5 --------
    let gradientLayer = CAGradientLayer()
    // ------- 6 --------
    gradientLayer.mask = gradientMask
    gradientLayer.frame = layer.frame
    gradientLayer.contentsScale = UIScreen.main.scale
    // ------- 7 --------
    gradientLayer.colors = [UIColor.gray.cgColor, UIColor.green.cgColor]
    // ------- 8 --------
    layer.addSublayer(gradientLayer)
}
0
m.eldehairy