LoginSignup
14
13

More than 3 years have passed since last update.

【Swift】UIBezierPathを使ってグラデーション付きの円弧を描く

Last updated at Posted at 2019-06-18

SS.png

UIBezierPathで描かれた図形にグラデーションを付ける方法が中々探しても見つからなかったので、備忘録も兼ねて投稿します。

UIViewのサブクラスを作り、ストーリーボード上に設置してみる

GradientArcView.swift
@IBDesignable class GradientArcView: UIView {

}

@IBDesignableアノテーションを付与すると、ストーリーボードで作業する際にリアルタイムでレンダリングしてくれるので便利です。
当然ながら、動作は重たくなりますが……。

SS3.png

作成したカスタムViewにAspectRatio1:1の制約をかけて画面中央に配置しています。

円弧を描く

UIViewのdraw(rect:)関数をオーバーライドして円弧を描きます。
この辺は詳しい記事がたくさんあるので簡単に。

GradientArcView.swift
override func draw(_ rect: CGRect) {
        let arcLayer = CAShapeLayer()
        let radius = rect.size.width / 2
        let lineWidth: CGFloat = 20
        let arcPath = UIBezierPath(arcCenter: CGPoint(x: rect.midX, y: rect.midY),
                               radius: radius - lineWidth,
                               startAngle: 0,
                               endAngle: CGFloat(Double.pi * 2),
                               clockwise: true)
        arcLayer.frame = rect
        arcLayer.path = arcPath.cgPath
        arcLayer.lineWidth = lineWidth
        arcLayer.fillColor = UIColor.clear.cgColor
        arcLayer.strokeColor = UIColor.red.cgColor
}

ここでaddSublayer()すれば円弧が表示されますが、マスクしていくのでまだ追加しません

円弧に重ねるためのグラデーションレイヤーを作る

GradientArcView.swift
        let gradientLayer = CAGradientLayer()
        gradientLayer.frame = rect
        gradientLayer.colors = [
            UIColor.orange.cgColor,
            UIColor.red.cgColor,
            UIColor.purple.cgColor,
            UIColor.blue.cgColor
        ]
        gradientLayer.startPoint = CGPoint(x: 0.0, y: 0.0)
        gradientLayer.endPoint = CGPoint(x: 1.0, y: 1.0)
        self.layer.addSublayer(gradientLayer)

draw(rect:)関数の中に続けて書いていきます。
CAGradientLayerのstartPoint、endPointはこのような関係になっています
SS4.png
左下が始点で右上が終点となるように書き換えてみます。

GradientArcView.swift
gradientLayer.startPoint = CGPoint(x: 0.0, y: 1.0)
gradientLayer.endPoint = CGPoint(x: 1.0, y: 0.0)

SS6.png
色の重なり順が変わりました。

グラデーションレイヤーでマスクする

.swift
gradientLayer.mask = arcLayer

スクリーンショット 2019-06-18 18.00.48.png

無事マスクされました。

コード全文

GradientArcView.swift

import UIKit

@IBDesignable class GradientArcView: UIView {

    override func draw(_ rect: CGRect) {
        let arcLayer = CAShapeLayer()
        let radius = rect.size.width / 2
        let lineWidth: CGFloat = 20

        let arcPath = UIBezierPath(arcCenter: CGPoint(x: rect.midX, y: rect.midY),
                               radius: radius - lineWidth,
                               startAngle: 0,
                               endAngle: CGFloat(Double.pi * 2),
                               clockwise: true)
        arcLayer.frame = rect
        arcLayer.path = arcPath.cgPath
        arcLayer.lineWidth = lineWidth
        arcLayer.fillColor = UIColor.clear.cgColor
        arcLayer.strokeColor = UIColor.red.cgColor

        let gradientLayer = CAGradientLayer()
        gradientLayer.frame = rect
        gradientLayer.colors = [
            UIColor.orange.cgColor,
            UIColor.red.cgColor,
            UIColor.purple.cgColor,
            UIColor.blue.cgColor
        ]
        gradientLayer.startPoint = CGPoint(x: 0.0, y: 1.0)
        gradientLayer.endPoint = CGPoint(x: 1.0, y: 0.0)
        self.layer.addSublayer(gradientLayer)

        gradientLayer.mask = arcLayer
    }
}

参考

Core Animation Framework Reference

14
13
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
13