Drawingと呼ばれる新しいシングルビューアプリプロジェクト
本当に複雑になると、複雑な描画に最適化されたAppleの低レベルフレームワークであるMetalに移行できます。SwiftUIの優れた機能の1つは、これら2つがほぼ互換性があることです。1つの小さな変更でコアアニメーションからメタルに移行できます。
SwiftUIでカスタムパスを作成する
Creating custom paths with SwiftUI
import SwiftUI struct ContentView: View { var body: some View { Path { path in path.move(to: CGPoint(x: 200, y: 100)) path.addLine(to: CGPoint(x: 100, y: 300)) path.addLine(to: CGPoint(x: 300, y: 300)) path.addLine(to: CGPoint(x: 200, y: 100)) //path.addLine(to: CGPoint(x: 100, y: 300)) } //.fill(Color.blue.opacity(0.25)) //.stroke(Color.blue.opacity(0.25), lineWidth: 10) .stroke(Color.blue, style: StrokeStyle(lineWidth: 10, lineCap: .round, lineJoin: .round)) } }
SwiftUIのパスとシェイプ
Paths vs shapes in SwiftUI
SwiftUIは、微妙に異なる2つのタイプ(パスと形状)を使用したカスタム描画を可能にします。パスは、「ここから始めて、ここまで線を引いて、そこに円を追加する」などの一連の描画手順であり、すべて絶対座標を使用しています。対照的に、形状は、それがどこで使用されるか、またはどのくらい使用されるかはわかりませんが、代わりに、指定された長方形の中にそれ自体を描くように求められます。
シェイプもビューです。つまり、テキストビューや画像などと一緒に使用できます。
import SwiftUI struct Triangle: Shape { func path(in rect: CGRect) -> Path { var path = Path() path.move(to: CGPoint(x: rect.midX, y: rect.minY)) path.addLine(to: CGPoint(x: rect.minX, y: rect.maxY)) path.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY)) path.addLine(to: CGPoint(x: rect.midX, y: rect.minY)) return path } } struct Arc: Shape { var startAngle: Angle var endAngle: Angle var clockwise: Bool func path(in rect: CGRect) -> Path { let rotationAdjustment = Angle.degrees(90) let modifiedStart = startAngle - rotationAdjustment let modifiedEnd = endAngle - rotationAdjustment var path = Path() path.addArc(center: CGPoint(x: rect.midX, y: rect.midY), radius: rect.width / 2, startAngle: modifiedStart, endAngle: modifiedEnd, clockwise: !clockwise) return path } /* func path(in rect: CGRect) -> Path { var path = Path() path.addArc(center: CGPoint(x: rect.midX, y: rect.midY), radius: rect.width / 2, startAngle: startAngle, endAngle: endAngle, clockwise: clockwise) return path } */ } struct ContentView: View { var body: some View { /* Triangle() .fill(Color.red) .frame(width: 300, height: 300) */ /*Triangle() .stroke(Color.red, style: StrokeStyle(lineWidth: 10, lineCap: .round, lineJoin: .round)) .frame(width: 300, height: 300) */ Arc(startAngle: .degrees(0), endAngle: .degrees(110), clockwise: true) .stroke(Color.blue, lineWidth: 10) .frame(width: 300, height: 300) } }
InsettableShapeによるstrokeBorder()サポートの追加
Adding strokeBorder() support with InsettableShape
stroke()
strokeBorder()
struct Arc: InsettableShape { var startAngle: Angle var endAngle: Angle var clockwise: Bool //----------------------- var insetAmount: CGFloat = 0 //----------------------- func inset(by amount: CGFloat) -> some InsettableShape { var arc = self arc.insetAmount += amount return arc } //----------------------- func path(in rect: CGRect) -> Path { let rotationAdjustment = Angle.degrees(90) let modifiedStart = startAngle - rotationAdjustment let modifiedEnd = endAngle - rotationAdjustment var path = Path() path.addArc(center: CGPoint(x: rect.midX, y: rect.midY), radius: rect.width / 2 - insetAmount, startAngle: modifiedStart, endAngle: modifiedEnd, clockwise: !clockwise) return path } } struct ContentView: View { var body: some View { //Circle() // .stroke(Color.blue, lineWidth: 40) // Circle() // .strokeBorder(Color.blue, lineWidth: 40) Arc(startAngle: .degrees(0), endAngle: .degrees(110), clockwise: true) .stroke(Color.blue, lineWidth: 10) .frame(width: 300, height: 300) } }