100 Days of SwiftUI(DAY 43(Project9 part 1))

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