UIBezierPath:描画メソッドと仕組み

著者: IT Sectr 公開日: 2026-07-21 読了時間: 8 分

UIBezierPathは、iOSの2Dグラフィック用のベクターパスをカプセル化するUIKitのクラスです。輪郭の幾何学的記述と描画機能を組み合わせ、直線、ベジェ曲線、円弧、長方形を作成できます。CGPathとは異なり、UIBezierPathは現在のグラフィックコンテキストで直接動作する独自の描画メソッドを持っています。Apple Developer Documentation, 2026によると、UIBezierPathはオブジェクト指向ラッパー内で全ての標準的なQuartz 2D操作をサポートしています。

重要なポイント

  • UIBezierPathはUIKitでベクターパスを扱うためのCGPathのオブジェクト指向ラッパーです。
  • move(to:)addLine(to:)はパスの直線セグメントを定義します。
  • addQuadCurve(to:controlPoint:)addCurve(to:controlPoint1:controlPoint2:)はベジェ曲線を構築します。
  • addArc(withCenter:radius:startAngle:endAngle:clockwise:)は円弧とセクターを作成します。
  • fillstrokeは追加オブジェクトを使わずに現在のコンテキストで直接パスを描画します。

UIBezierPathとは?

UIBezierPathはUIKitフレームワークのクラスで、NSObjectを継承し、NSCopying、NSSecureCodingを実装しています。ベクターパスの構築と描画のための高レベルなObjective-C/Swift APIを提供します。内部的には、UIBezierPathはCGPathRef(Core Graphicsオブジェクト)への参照を保存しますが、描画、ジオメトリ変更、スタイル管理のための便利なメソッドを追加します。

CGPathを直接使用する場合と比較したUIBezierPathの主な利点は、組み込みの描画メソッドです。UIBezierPathインスタンスでfill()またはstroke()を呼び出すと、自動的にコンテキストが設定され、パスが描画されます。このクラスはlineWidth、lineCapStyle、lineJoinStyle、miterLimit、flatnessプロパティもサポートしており、スタイルを保存するための別個のオブジェクトなしで外観を制御できます。

UIBezierPathは、ほとんどのiOSアプリケーションでUIView内のカスタム描画に使用されています。シンプルなアイコンから複雑なアニメーションチャートまで幅広く使われています。UIViewクラスのdraw(_:)メソッドは、開発者がUIBezierPathを作成して描画する主要な場所です。このクラスはCore Animationと完全に互換性があり、CAShapeLayerとCABasicAnimationを介したパスアニメーションに使用できます。

直線と長方形

move(to:)メソッドは、描画せずにパスの開始点を指定された座標に移動します。これはセグメントを構築する前の必須の呼び出しです。addLine(to:)は現在位置から指定された点まで直線セグメントを追加します。close()メソッドは、最後の点から最後のmove(to:)の最初の点まで線を描画して輪郭を閉じます。

角丸長方形

UIBezierPathは、既成の図形のためのいくつかの便利なイニシャライザを提供します。init(rect:)は長方形を作成し、init(roundedRect:cornerRadius:)は角丸長方形を作成します。UIRectCornerパラメータを使用すると、topLeftやbottomRightなど選択した角のみを丸め、残りは直線のままにできます。これはカスタムボタンやカードの作成に広く使用されています。

init(ovalIn:)は指定された長方形に内接する楕円を作成します。長方形が正方形の場合、楕円は円になります。init(roundedRect:byRoundingCorners:cornerRadii:)は最も柔軟なオプションで、各コーナーに異なる半径を設定できます。このイニシャライザはiOS 6で導入され、角丸コンテナを作成するための標準であり続けています。

swift
let path = UIBezierPath()
path.move(to: CGPoint(x: 50, y: 50))
path.addLine(to: CGPoint(x: 200, y: 50))
path.addLine(to: CGPoint(x: 200, y: 150))
path.addLine(to: CGPoint(x: 125, y: 200))
path.addLine(to: CGPoint(x: 50, y: 150))
path.close()

ベジェ曲線:2次と3次

addQuadCurve(to:controlPoint:)は1つの制御点を持つ2次ベジェ曲線を追加します。このタイプの曲線は、計算を最小限に抑えたい場合の単純な滑らかな曲がりに使用されます。2次曲線は常に放物線であり、始点、制御点、終点によって形成される三角形の内側にあることが保証されています。

3次ベジェ曲線

addCurve(to:controlPoint1:controlPoint2:)は2つの制御点を持つ3次ベジェ曲線を追加します。3次曲線は、すべての最新のベクターエディターとTrueTypeフォントで使用されています。2つの制御点により、形状を正確に制御するためのより多くの自由度が得られます。このメソッドは、有機的で複雑な輪郭を構築するために推奨されます。

曲線を構築する際には、連続性の原理を維持することが重要です。セグメントの接続点での滑らかさのことです。C1連続性(接線)の場合、次の曲線の制御点は前の曲線の制御点と同じ線上にある必要があります。C2連続性(曲率)の場合、より複雑な調整が必要ですが、同じ数の制御点を持つ2つのUIBezierPath間でアニメーションする場合、CAShapeLayerで自動的に提供されます。

メソッドタイプ制御点次数
addQuadCurve2次ベジェ12
addCurve3次ベジェ23
addArc円弧

円弧と円

addArc(withCenter:radius:startAngle:endAngle:clockwise:)は指定されたパラメータで円弧を追加します。角度は円の中心を基準にラジアンで指定します。ゼロ角度は右方向(時計の3時の位置)に対応します。clockwiseパラメータは方向を決定します。trueは時計回り、falseは反時計回りです。円弧は円グラフ、スピードメーター、インタラクティブなプログレスリングに不可欠です。

円とセクター

完全な円の場合は、startAngle = 0、endAngle = .pi * 2を使用します。セクター(円グラフの一部)を作成するには、addArcの後に中心へのaddLine(to:)とclose()を使用します。UIBezierPathには組み込みのaddCircleメソッドはありません。円は正方形の長方形でinit(ovalIn:)を使用するか、完全な角度でaddArcを使用して作成します。

addArc(withCenter:radius:startAngle:endAngle:clockwise:)メソッドは、現在位置が一致しない場合、自動的に円弧の開始点にmove(to:)を実行します。現在位置が異なる場合、その位置と円弧の開始点の間に直線が描画されます。この動作はCore Graphicsとは異なります。Core Graphicsでは新しい輪郭ごとに明示的なmove(to:)が必要です。

swift
let center = CGPoint(x: 150, y: 150)
let slice = UIBezierPath()
slice.move(to: center)
slice.addArc(
    withCenter: center,
    radius: 100,
    startAngle: 0,
    endAngle: .pi * 0.75,
    clockwise: true
)
slice.close()

パスの塗りつぶしとストローク

fill()は、現在のfillColorまたはsetFill()を介してグラフィックコンテキストに設定された色でパスの内部領域を塗りつぶします。自己交差するパスの場合、塗りつぶしルールはusesEvenOddFillRuleプロパティによって決定されます。trueの場合、偶数-奇数ルールが使用されます。点から出る光線が輪郭を奇数回交差する場合、その点は図形の内部と見なされます。

ストローク設定

stroke()は現在のlineWidth、lineCapStyle、lineJoinStyle設定でパスの輪郭を描画します。lineCapStyleは開いたセグメントの端の形状を定義します。.butt(まっすぐ切断)、.round(半円形)、.square(突起のある正方形)。lineJoinStyleはコーナーの結合部の形状を定義します。.miter(鋭角)、.round(丸み)、.bevel(面取り)。

破線にはsetLineDash(_:count:phase:)プロパティを使用します。交互のダッシュとギャップの長さの配列、要素数、初期フェーズを受け入れます。ダッシュのレンダリングはパスのラスタライズ中に行われます。複雑なパターンでも輪郭の幾何学的複雑さは増加しません。CAShapeLayerは、開始から終了までの“描画”効果のためにstrokeEndプロパティのアニメーションをサポートしています。

swift
override func draw(_ rect: CGRect) {
    let path = UIBezierPath(ovalIn: CGRect(x: 50, y: 50, width: 200, height: 200))
    UIColor.blue.setFill()
    UIColor.black.setStroke()
    path.lineWidth = 4
    path.fill()
    path.stroke()
}

複雑な図形作成の例

UIBezierPathを使用してリング形式のカスタムプログレスインジケータを作成しましょう。リングは異なるストローク色を持つ同じ半径の2つの円弧から構築されます。最初の円弧は灰色の完全な円(背景)、2つ目は進行状況を示すセグメントです。アニメーションにはCAShapeLayerとCABasicAnimationを使用します。

swift
class RingView: UIView {

    private let progressLayer = CAShapeLayer()

    override func layoutSubviews() {
        super.layoutSubviews()
        let center = CGPoint(x: bounds.midX, y: bounds.midY)
        let radius = bounds.width * 0.4
        let lineWidth: CGFloat = 12

        let backgroundRing = UIBezierPath()
        backgroundRing.addArc(withCenter: center, radius: radius,
                          startAngle: -.pi / 2, endAngle: .pi * 1.5, clockwise: true)

        progressLayer.path = backgroundRing.cgPath
        progressLayer.strokeColor = UIColor.systemBlue.cgColor
        progressLayer.lineWidth = lineWidth
        progressLayer.lineCap = .round
        progressLayer.fillColor = UIColor.clear.cgColor
        progressLayer.strokeEnd = 0
        layer.addSublayer(progressLayer)
    }

    func animateProgress(to value: CGFloat) {
        CABasicAnimation(keyPath: "strokeEnd").apply {
            $0.toValue = value
            $0.duration = 1.5
            $0.timingFunction = CAMediaTimingFunction(name: .easeOut)
            progressLayer.add($0, forKey: nil)
        }
        progressLayer.strokeEnd = value
    }
}

この例では、UIBezierPathを使用して円形の輪郭を作成し、cgPathプロパティを介してCAShapeLayerに渡します。strokeEndを0から1にアニメーション化すると、リングの塗りつぶしが可視化されます。このアプローチは、ローディングインジケータ、フィットネストラッカー、プログレスウィジェットで使用されています。layoutSubviewsメソッドは、Viewのサイズが変更されたときにパスの再構築を保証します。

lineCap = .roundは円弧に丸みを帯びた端を追加し、インジケータによりきれいな外観を与えます。strokeEndプロパティはCAShapeLayerのアニメーション可能なプロパティであり、フレームごとに輪郭全体を再描画する必要はありません。アニメーションはCore Animationを介して完全にGPU上で実行され、CPUに負荷をかけずに60 FPSを保証します。

よくある質問

UIBezierPathとCGPathの違いは?

UIBezierPathはCGPathのオブジェクト指向ラッパーで、組み込みのfill()およびstroke()メソッドを含みます。CGPathはCore Graphicsの不変のCオブジェクトであり、CGContextを介した明示的な描画が必要です。UIBezierPathはUIKitに便利で、CGPathは再利用に効率的です。

長方形の上の角だけを丸めるには?

roundedRectに.topLeftと.topRightパラメータを指定してinit(roundedRect:byRoundingCorners:cornerRadii:)を使用します。これは複雑な複合パスを作成せずに選択的に角を丸めることができる唯一のUIBezierPathメソッドです。

異なるスタイルでUIBezierPathを再利用するには?

cgPathプロパティは不変のCGPathRefを返し、CAShapeLayerに渡したり、異なる色や太さで使用したりできます。UIBezierPathの変更(点の移動)は、明示的に更新されるまで以前に取得したcgPathに影響しません。

fill()がパス全体をカバーしないのはなぜ?

usesEvenOddFillRuleを確認してください。輪郭に自己交差がある場合、偶数-奇数ルールにより領域が塗りつぶされないままになることがあります。標準のnon-zero winding塗りつぶしルールにはusesEvenOddFillRule = falseを設定します。

UIBezierPathの形状をアニメーション化するには?

CAShapeLayerでキーパス「path」を使用してCABasicAnimationを使用します。両方のパス状態に同じ数のセグメントと制御点が含まれている必要があります。そうしないと、アニメーションがぎくしゃくしたり失敗したりします。

まとめ

  • UIBezierPathはベクターパスと2Dグラフィックを扱うためのUIKitのオブジェクト指向クラスです。
  • move(to:)addLine(to:)は直線と多角形を構築するための基本メソッドです。
  • addQuadCurveaddCurveは1つと2つの制御点で2次と3次のベジェ曲線を作成します。
  • addArcは柔軟な角度と方向制御で円弧を描画します。
  • fill()stroke()は現在のグラフィックコンテキストで直接描画を実行します。
  • イニシャライザinit(roundedRect:)init(ovalIn:)は標準形状の作成を高速化します。
  • cgPathプロパティにより、UIBezierPathをCore AnimationやCAShapeLayerと統合してアニメーション化できます。

ターンキー方式のモバイルアプリケーションを開発します

IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。

プロジェクトについて相談

こちらもお読みください