Pathビューを使った図形の描画方法について解説します。
環境
この記事の情報は次のバージョンで動作確認しています。
【Swift】5.2.4
【iOS】13.6
【macOS】Catalina バージョン 10.15.6
基本的な使い方
1 2 3 4 5 |
Path { path in // 引数pathに対して描画メソッドを追加 } |
クロージャー内で受け取った引数path(空のPathビュー)に描画メソッドを追加して、2次元のアウトライン形状の図形を作成します。
使用例1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
struct ContentView: View { var body: some View { Path { path in path.move(to: CGPoint(x: 100, y: 0)) // 始点移動 path.addLine(to: CGPoint(x: 200, y: 200)) // 直線描画 path.addLine(to: CGPoint(x: 0, y: 200)) path.addLine(to: CGPoint(x: 100, y: 0)) } .fill(Color.red) // 塗りつぶし色指定 .frame(width: 200, height: 200) } } |
Pathビューのクロージャー内で三角形のアウトラインを描画を定義し、.fill()モディファイアで図形の塗りつぶし色を指定します。
1 2 3 4 5 6 |
} .stroke() // 枠線描画指定 .fill(Color.red) .frame(width: 200, height: 200) |
.fill()モディファイアの前に、.stroke()モディファイアを指定すると、枠線のみの描画になります。
.storoke()と.fill()を省略した場合は、次のように黒(Color.primary)で塗りつぶされた図形が描画されます。
これは.fill(引数なし)が指定された場合と同じ動作です。
使用例2
出力結果は使用例1と同じですが、次のような表記も可能です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
struct ContentView: View { var body: some View { var path = Path() path.move(to: CGPoint(x:100, y:0)) path.addLine(to: CGPoint(x: 200, y: 200)) path.addLine(to: CGPoint(x: 0, y: 200)) path.addLine(to: CGPoint(x: 100, y: 0)) return path .fill(Color.red) .frame(width: 200, height: 200) } } |
一旦空のPathをプロパティに代入し、そこに描画メソッドを追加する手法です。
複雑な描画指示を記述する場合は、こちらの書き方の方が使い勝手が良いかもしれません。
以降の章で、Pathビューで使える基本メソッドを紹介します。
move
1 2 3 |
move(to: CGPoint) |
パスの始点をCGPoint構造体で指定します。
使用例
途中でパスの始点を移動して、2本の線を追加する例です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
struct ContentView: View { var body: some View { Path { path in path.move(to: CGPoint(x: 0, y: 0)) path.addLine(to: CGPoint(x: 200, y: 200)) path.move(to: CGPoint(x: 200, y: 0)) path.addLine(to: CGPoint(x: 0, y: 200)) } .stroke(lineWidth: 5) .fill(Color.red) .frame(width: 200, height: 200) } } |
addLine
1 2 3 |
addLine(to: CGPoint) |
現在の位置から引数(to)で指定した位置までの直線を追加します。
続けて使用すると連続線となります。
使用例
線の組み合わせで3角形を描画する例です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
struct ContentView: View { var body: some View { Path { path in path.move(to: CGPoint(x: 100, y: 0)) path.addLine(to: CGPoint(x: 200, y: 200)) path.addLine(to: CGPoint(x: 0, y: 200)) path.addLine(to: CGPoint(x: 100, y: 0)) } .stroke(lineWidth: 20) .fill(Color.red) .frame(width: 200, height: 200) } } |
頂点の角だけ他と形状が異なるのは、この部分が連続線になっていない為です。
連続線にするには後に示すcloseSubpathメソッドを使用します。
closeSubpath
1 2 3 |
closeSubpath() |
パスの現在位置から開始点に直線を追加し、現在のパスを閉じます。
使用例
三角形の描画で、最後の直線にcloseSubpath()を使用した例です。
全てaddLineで描画した場合と違い、最初と最後の線が連続線になります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
struct ContentView: View { var body: some View { Path { path in path.move(to: CGPoint(x: 100, y: 0)) path.addLine(to: CGPoint(x: 200, y: 200)) path.addLine(to: CGPoint(x: 0, y: 200)) path.closeSubpath() } .stroke(lineWidth: 20) .fill(Color.red) .frame(width: 200, height: 200) } } |
addLines
1 2 3 |
addLines([CGPoint]) |
連続した直線をパスに追加します。
各直線の両端位置はCGPoint構造体の配列で指定します。
addLines()を使用した場合、最初のポイントが開始位置になりますので、moveメソッドで開始位置を指定する必要がありません。
使用例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
struct ContentView: View { var body: some View { Path { path in path.addLines([ CGPoint(x: 0, y: 0), CGPoint(x: 200, y: 0), CGPoint(x: 0, y: 200), CGPoint(x: 200, y: 200) ]) path.closeSubpath() } .stroke(lineWidth: 5) .fill(Color.blue) .frame(width: 200, height: 200) } } |
AddArc
1 2 3 |
addArc(center: CGPoint, radius: CGFloat, startAngle: Angle, endAngle: Angle, clockwise, transform: CGAffineTransform) |
円周の一部分である円弧をパスに追加します。
center
円弧の中心
CGPoint構造体で指定します
radius
円弧の半径
CGFloat型で指定します
startAngle、endAngle
円弧の開始角度と終了角度
Angle構造体で指定します
clockwise
回転方向をtrue/falseで指定します
true:時計と反対回り
false:時計回り
transform(省略可能)
図形変換情報(アフィン変換行列)
CGAffineTransformt構造体で指定します
使用例
円弧と中心線をつなげて扇形を描画した例です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
struct ContentView: View { var body: some View { Path { path in path.addArc( center: CGPoint(x: 100, y: 100), radius: 100, startAngle: .degrees(-90), endAngle: .degrees(0), clockwise: false ) path.addLine(to: CGPoint(x: 100, y: 100)) path.closeSubpath() } .stroke(lineWidth: 5) .fill(Color.pink) .frame(width: 200, height: 200) } } |
addRect、addRects
1 2 3 |
addRect(CGRect, transform: CGAffineTransform) |
矩形(長方形)をパスに追加します。
矩形はCGRect構造体で指定します。
transformは図形変換情報(アフィン変換行列)をCGAffineTransformt構造体で指定します。
こちらは省略可能です。
1 2 3 |
addRects([CGRect], transform: CGAffineTransform) |
こちらは複数の矩形をまとめてパスに追加するメソッドです。
使用例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
struct ContentView: View { var body: some View { Path { path in path.addRects([ CGRect(x: 25, y: 25, width: 100, height: 100), CGRect(x: 50, y: 50, width: 100, height: 100), CGRect(x: 75, y: 75, width: 100, height: 100) ]) } .stroke(lineWidth: 5) .fill(Color.green) .frame(width: 200, height: 200) } } |
addEllipse
1 2 3 |
addEllipse(in: CGRect, transform: CGAffineTransform) |
楕円形をパスに追加します。
CGRect構造体で指定した矩形にぴったり収まる楕円形を描画します。
transformは図形変換情報(アフィン変換行列)をCGAffineTransformt構造体で指定します。
こちらは省略可能です。
次のイニシャライザを使うと、はじめから楕円形を追加したPathを生成する事ができます。
1 2 3 |
Path(ellipseIn: CGRect) |
使用例
1 2 3 4 5 6 7 8 9 10 11 |
struct ContentView: View { var body: some View { Path { path in path.addEllipse(in: CGRect(x:0, y: 0, width: 200, height: 100)) } .fill(Color.yellow) .frame(width: 200, height: 100) } } |
または、
1 2 3 4 5 6 7 8 9 |
struct ContentView: View { var body: some View { Path(ellipseIn: CGRect(x:0, y: 0, width: 200, height: 100)) .fill(Color.yellow) .frame(width: 200, height: 100) } } |
addRoundedRect
1 2 3 |
addRoundedRect(in: CGRect, cornerSize: CGSize, transform: CGAffineTransform) |
角丸四角形をパスに追加します。
CGRect構造体で指定した矩形にぴったり収まる角丸四角形を描画します。
角丸のサイズはCGSize構造体で指定します。
transformは図形変換情報(アフィン変換行列)をCGAffineTransformt構造体で指定します。
こちらは省略可能です。
次のイニシャライザを使うと、はじめから角丸四角形を追加したPathを生成する事ができます。
1 2 3 4 |
Path(roundedRect: CGRect, cornerSize: CGSize) // 角丸をCGSizeで指定 Path(roundedRect: CGRect, cornerRadius: CGFloat) // 角丸の半径を指定 |
使用例
1 2 3 4 5 6 7 8 9 10 11 |
struct ContentView: View { var body: some View { Path { path in path.addRoundedRect(in: CGRect(x: 0, y: 0, width: 200, height: 100), cornerSize: CGSize(width: 30, height: 30)) } .fill(Color.orange) .frame(width: 200, height: 100) } } |
または、
1 2 3 4 5 6 7 8 9 |
struct ContentView: View { var body: some View { Path(roundedRect: CGRect(x:0, y:0, width:200, height:100), cornerSize: CGSize(width:30, height: 30)) .fill(Color.orange) .frame(width: 200, height: 100) } } |
または、
1 2 3 4 5 6 7 8 9 |
struct ContentView: View { var body: some View { Path(roundedRect: CGRect(x:0, y:0, width:200, height:100), cornerRadius: 30) .fill(Color.orange) .frame(width: 200, height: 100) } } |
その他
Pathビューには、ここに紹介した以外にもいろいろな描画用メソッドが用意されています。
もっと詳しく知りたい方は、Swiftのリファレンスを参照してみて下さい。