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)
}
}