CAShapeLayerにグラデーションを適用した経験はありますか? CAShapeLayerは素晴らしいレイヤークラスですが、塗りつぶしの塗りつぶしのみをサポートしているように見えますが、グラデーション塗りつぶし(実際にはアニメーション化可能なグラデーション)が必要です。
CAShapeLayerで行うその他すべて(シャドウ、シェイプ、ストロークカラー、アニメート可能なシェイプパス)は素晴らしいものです。
CAGradientLayerをCAShapeLayer内に配置するか、実際にCAShapeLayerをGradientLayerのマスクとして設定し、両方をコンテナーレイヤーに追加しようとしましたが、これらには正しい結果がありません。
CAShapeLayerをサブクラス化する必要がありますか、それともより良い方法がありますか?
ありがとう。
次のように、形状のパスを使用してマスキングレイヤーを作成し、グラデーションレイヤーに適用できます。
UIView *v = [[UIView alloc] initWithFrame:self.window.frame];
CAShapeLayer *gradientMask = [CAShapeLayer layer];
gradientMask.fillColor = [[UIColor clearColor] CGColor];
gradientMask.strokeColor = [[UIColor blackColor] CGColor];
gradientMask.lineWidth = 4;
gradientMask.frame = CGRectMake(0, 0, v.bounds.size.width, v.bounds.size.height);
CGMutablePathRef t = CGPathCreateMutable();
CGPathMoveToPoint(t, NULL, 0, 0);
CGPathAddLineToPoint(t, NULL, v.bounds.size.width, v.bounds.size.height);
gradientMask.path = t;
CAGradientLayer *gradientLayer = [CAGradientLayer layer];
gradientLayer.startPoint = CGPointMake(0.5,1.0);
gradientLayer.endPoint = CGPointMake(0.5,0.0);
gradientLayer.frame = CGRectMake(0, 0, v.bounds.size.width, v.bounds.size.height);
NSMutableArray *colors = [NSMutableArray array];
for (int i = 0; i < 10; i++) {
[colors addObject:(id)[[UIColor colorWithHue:(0.1 * i) saturation:1 brightness:.8 alpha:1] CGColor]];
}
gradientLayer.colors = colors;
[gradientLayer setMask:gradientMask];
[v.layer addSublayer:gradientLayer];
シャドウも使用する場合は、シェイプレイヤーの「複製」をグラデーションレイヤーの下に配置し、同じパス参照をリサイクルする必要があります。
@Palimondoに素晴らしい回答をありがとう!
誰かがSwift 4 + filling animationこのソリューションのコードを探している場合:
let myView = UIView(frame: .init(x: 0, y: 0, width: 200, height: 150))
view.addSubview(myView)
myView.center = view.center
// Start and finish point
let startPoint = CGPoint(x: myView.bounds.minX, y: myView.bounds.midY)
let finishPoint = CGPoint(x: myView.bounds.maxX, y: myView.bounds.midY)
// Path
let path = UIBezierPath()
path.move(to: startPoint)
path.addLine(to: finishPoint)
// Gradient Mask
let gradientMask = CAShapeLayer()
let lineHeight = myView.frame.height
gradientMask.fillColor = UIColor.clear.cgColor
gradientMask.strokeColor = UIColor.black.cgColor
gradientMask.lineWidth = lineHeight
gradientMask.frame = myView.bounds
gradientMask.path = path.cgPath
// Gradient Layer
let gradientLayer = CAGradientLayer()
gradientLayer.startPoint = CGPoint(x: 0.0, y: 0.5)
gradientLayer.endPoint = CGPoint(x: 1.0, y: 0.5)
// make sure to use .cgColor
gradientLayer.colors = [UIColor.red.cgColor, UIColor.green.cgColor]
gradientLayer.frame = myView.bounds
gradientLayer.mask = gradientMask
myView.layer.addSublayer(gradientLayer)
// Corner radius
myView.layer.cornerRadius = 10
myView.clipsToBounds = true
追加。 「塗りつぶしアニメーション」も必要な場合は、次の行を追加します。
// Filling animation
let animation = CABasicAnimation(keyPath: "strokeEnd")
animation.fromValue = 0
animation.duration = 10
gradientMask.add(animation, forKey: "LineAnimation")
これは優れたソリューションですが、すぐにビューがないCAShapeLayerでカテゴリを作成すると、予期しない問題が発生する可能性があります。
参照 新しく作成されたCAShapeLayerの正しいフレームの設定
結論として、パスの境界を取得し、パスの境界を使用してグラデーションマスクのフレームを設定し、必要に応じて変換します。ここでの良い点は、他のフレームではなくパスの境界を使用することで、グラデーションがパスの境界内にのみ収まることです(これが必要な場合)。
// Category on CAShapeLayer
CGRect pathBounds = CGPathGetBoundingBox(self.path);
CAShapeLayer *gradientMask = [CAShapeLayer layer];
gradientMask.fillColor = [[UIColor blackColor] CGColor];
gradientMask.frame = CGRectMake(0, 0, pathBounds.size.width, pathBounds.size.height);
gradientMask.path = self.path;
CAGradientLayer *gradientLayer = [CAGradientLayer layer];
gradientLayer.startPoint = CGPointMake(0.5,1.0);
gradientLayer.endPoint = CGPointMake(0.5,0.0);
gradientLayer.frame = CGRectMake(0, 0, pathBounds.size.width, pathBounds.size.height);
NSMutableArray *colors = [NSMutableArray array];
for (int i = 0; i < 10; i++) {
[colors addObject:(id)[[UIColor colorWithHue:(0.1 * i) saturation:1 brightness:.8 alpha:1] CGColor]];
}
gradientLayer.colors = colors;
[gradientLayer setMask:gradientMask];
[self addSublayer:gradientLayer];