Swift CAShapeLayerで図形にグラデーションをつける方法

UIViewにCAShapeLayerを补充し図形を表示できる。CAShapeLayerのプロパティには,fillColor(背景を涂る色指定)やstrokeColor(図形の轮郭を书く时の色指定)が用意されているので,简単に図形に色を涂ることができる。

ではCAShapeLayerで背景色にグラデーションショ场合はどうするのか?

毎回忘れるのと误解していたので整理がてらメモ。

CALayerの面膜

ayラデーションを付ける前にCALayerのmaskの机能を见てみる。

口罩— CALayer | Apple开发人员文档

var mask: CALayer? { get set } 

を,别のCALayerを面具にセットすると,もともとのCAlayerの図形が「マスク」され部分的に表示されるという机能である。

面具サンプル

赤い星のCAShapeLayerに黒丸4つのCAShapeLayerをmaskとして设定すると,星の一部が切り抜かれて表示される。

黒丸4つのマスクと重なった部分が表示されたのだ。

如Swiftコード。

  • 黒丸マスクCAShapeLayer
 // mask path 
let maskpath = CGMutablePath()
maskpath.addEllipse(in: CGRect(x: 10, y: 10, width:30, height:30))
maskpath.addEllipse(in: CGRect(x: 10, y: 60, width:30, height:30))
maskpath.addEllipse(in: CGRect(x: 60, y: 10, width:30, height:30))
maskpath.addEllipse(in: CGRect(x: 60, y: 60, width:30, height:30))
 // show path on layer 
let maskLayer = CAShapeLayer()
maskLayer.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
maskLayer.path = maskpath
maskLayer.fillColor = UIColor.black.cgColor
  • 星マスクCAShapeLayer
 // create path of ☆ 
let starPath = CGMutablePath()
starPath.move(to: CGPoint(x:19.098,y:100))
starPath.addLine(to: CGPoint(x:25,y:63.82))
starPath.addLine(to: CGPoint(x:-0,y:38.197))
starPath.addLine(to: CGPoint(x:34.549,y:32.918))
starPath.addLine(to: CGPoint(x:50,y:-0))
starPath.addLine(to: CGPoint(x:65.451,y:32.918))
starPath.addLine(to: CGPoint(x:100,y:38.197))
starPath.addLine(to: CGPoint(x:75,y:63.82))
starPath.addLine(to: CGPoint(x:80.902,y:100))
starPath.addLine(to: CGPoint(x:50,y:82.918))
starPath.closeSubpath()
 // show path on layer 
let shapeLayer = CAShapeLayer()
shapeLayer.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
shapeLayer.path = starPath
 shapeLayer.strokeColor = UIColor.red.cgColor 
shapeLayer.lineWidth = 2
shapeLayer.fillColor = UIColor.red.cgColor
shapeLayer.borderColor = UIColor.gray.cgColor
  • 星マスクに黒丸マスクをつけてUIViewに表示
 shapeLayer.mask = maskLayer 
view.layer.addSublayer(shapeLayer)

アニメーションする面具

今度はさっきの赤い星に,アニメーションする円をmaskとして指定してみよう。

期待通り,星型と円が重なるものがアニメーション表示された。

  • アニメーションする円のSwiftコード
 // mask path 
let maskpath = CGMutablePath()
maskpath.addEllipse(in: CGRect(x: 50, y: 50, width: 0, height: 0))
 let maskpath2 = CGMutablePath() 
maskpath2.addEllipse(in: CGRect(x: 0, y: 0, width: 100, height: 100))
 let maskLayer = CAShapeLayer() 
maskLayer.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
maskLayer.path = maskpath
 maskLayer.fillColor = UIColor.black.cgColor 
 // アニメーション指定
let pathKeyframe = CAKeyframeAnimation(keyPath: "path")
pathKeyframe.values = [maskpath,maskpath2,maskpath]
pathKeyframe.keyTimes = [0, 0.5, 1]
pathKeyframe.duration = 3.0
pathKeyframe.repeatDuration = CFTimeInterval.infinity
pathKeyframe.isRemovedOnCompletion = false
maskLayer.add(pathKeyframe, forKey: "path")

それで,図形にグラデーションをつける方法は?

グラデーションを描くCAGradientLayerというCALayerがある。そのCAGradientLayerのmaskに希望する形のCALayerを指定すればよいのだ。

CAGradientLayerでグラデーション描くとこうなった。

  • CAGradientLayerグラデーションのSwiftコード
 let gradLayer = CAGradientLayer() 
gradLayer.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
gradLayer.colors = [
UIColor.red.cgColor,
UIColor.blue.cgColor,
]
view.layer.addSublayer(gradLayer)

しちゃえばよさそう,このグラデーションをマスクしちゃえばよさそう。

 gradLayer.mask = maskLayer 

何を勘违いしていたか

作画ソフトを使うと図形にグラデーションショとうイうイメージなので,CAShapeLayerにグラデーションション用用用ロパティがあるかと思っていました…グラデーションをマスクするのですね。どうもこのあたりに违和感がありましたが,きちんと调べたら理解できました。

もちろんCALayerやUIViewを自前で描画する方法もあると思いますが,一例として。

参考

  • 口罩— CALayer | Apple开发人员文档
  • CAShapeLayer —核心动画| Apple开发人员文档
  • CAGradientLayer —核心动画| Apple开发人员文档