---
description: ╱🚧 under construction -> Canvas, Shape 必須具備甚麼特質？
---

# Shape

[SwiftUI](..) ⟩ [shapes]() ⟩ Shape  (protocol)

{% hint style="success" %}
<img src="https://1830103165-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M5-JmwCZMKh_d7RfBaN%2Fuploads%2F3B87hqej0rIvxYpR0crQ%2Fpush-out.jpg?alt=media&#x26;token=ba0b9aed-9d54-4ba4-844d-4dd2ff648614" alt="Shape is push-out view." data-size="line"> <mark style="color:purple;">`Shape`</mark> is a "<mark style="color:red;">**push-out**</mark>" view.
{% endhint %}

```swift
// protocol definition
protocol Shape : Sendable, Animatable, View, _RemoveGlobalActorIsolation
```

{% hint style="warning" %}
If you need the efficiency or flexibility of immediate mode drawing — for example, to create particle effects — use a [`Canvas`](https://developer.apple.com/documentation/swiftui/canvas) view instead.
{% endhint %}

{% tabs %}
{% tab title="💈" %}
* [uparrowshape](../view/view/.dimension/uparrowshape "mention")
* [gridlinesshape](shape/helper-shapes/gridlinesshape "mention")
* [lineshape](shape/helper-shapes/lineshape "mention")
* [vehicle.carbodyshape](shape/sports-car-in-sunset/vehicle.carbodyshape "mention")
* [polygon](shape/polygon "mention") - an animatable polygon shape.
{% endtab %}

{% tab title="⭐️" %}
{% hint style="info" %}
What's the difference between Shape and Path:question:

* Path 是一個 struct，主要是用**絕對座標** (absolute coordinates) 來畫路徑。
* Shape 是一個 protocol，除了可以用絕對座標畫路徑外，必要實現的 [.path(in: rect)](https://developer.apple.com/documentation/swiftui/shape/path\(in:\)) 方法也提供了一個 CGRect 參數，讓我們可以根據 container 的**相對位置**來畫路徑。

:point\_right: Hacking with Swift - [Paths vs shapes in SwiftUI](https://www.hackingwithswift.com/books/ios-swiftui/paths-vs-shapes-in-swiftui)
{% endhint %}
{% endtab %}

{% tab title="📜" %}
![](https://1830103165-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M5-JmwCZMKh_d7RfBaN%2F-MIddqEpjbhO15myOPEj%2F-MIde6Y5WyCqSBMj0SNd%2FAnimatable%20protocol.png?alt=media\&token=336ebcb8-8b17-40e8-b62b-f9533958767b)
{% endtab %}

{% tab title="📘 " %}
* [SwiftUI](https://developer.apple.com/documentation/swiftui) ⟩ [Shapes](https://developer.apple.com/documentation/swiftui/shapes) ⟩ [Shape](https://developer.apple.com/documentation/swiftui/shape) ⟩ &#x20;
  * [.fill(\_:style:)](https://developer.apple.com/documentation/swiftui/shape/fill\(_:style:\))
* SwiftUI  ⟩ &#x20;
  * [Shape](https://developer.apple.com/documentation/swiftui/shape)
  * [InsettableShape](https://developer.apple.com/documentation/swiftui/insettableshape)
* SwiftOnTap ⟩ View ⟩ [.clipShape(\_:style:)](https://swiftontap.com/view/clipshape\(_:style:\)) → some View
{% endtab %}

{% tab title="📗" %}
* [ ] AppCoda - [用 SwiftUI Path 建立折線圖](https://www.appcoda.com.tw/swiftui-path/)
* [ ] Big Mountain Studio ⟩ [The SwiftUI Shapes Live Series](https://www.bigmountainstudio.com/view/courses/shapes)
* [ ] objc.io - [SwiftUI: Paths vs. Shapes](https://www.objc.io/blog/2019/08/20/paths-vs-shapes/)
* [ ] Sarun ⟩ [SwiftUI basic Shape operations](https://sarunw.com/posts/swiftui-basic-shape-operations/)
{% endtab %}

{% tab title="👥 " %}
* [🌀 Shape](shape/shape)
* [shape](shape "mention")：shape.fill(content) 的填充樣式 content 是 [shapestyle](shapestyle "mention")。
* [🅿️ ShapeStyle](shapestyle)
* inherits from [view](../view/view "mention"), Animatable.
* [path](path "mention") conforms to Shape.
* can have [anim](../anim "mention").
* can be [fill](shape/fill "mention")ed.
* can be <mark style="color:red;">**clipped**</mark> using [even-odd-fill-mode](shape/fill/even-odd-fill-mode "mention").
{% endtab %}

{% tab title="🛠" %}
* [SVG to SwiftUI Shape](https://quassum.github.io/SVG-to-SwiftUI/)
{% endtab %}

{% tab title="🗣" %}
* [How can I clip a Shape with another Shape in SwiftUI?](https://stackoverflow.com/a/67128123/5409815) ⭐️
{% endtab %}

{% tab title="🐞" %}
* :lady\_beetle: [has-non-sendable-type](../../swift/concurrency/sendable/has-non-sendable-type "mention")
{% endtab %}
{% endtabs %}

## Examples

{% tabs %}
{% tab title="ContentView" %}
![](https://1830103165-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M5-JmwCZMKh_d7RfBaN%2Fuploads%2FL0o4nsm83zQoSVbrCo6d%2Fshapes.png?alt=media\&token=ade8b930-93f9-4557-b73b-443c16dd4ba1)

```swift
import SwiftUI
import PlaygroundSupport

// ContentView
struct ContentView: View {
    
    // body
    var body: some View {
        VStack{
            hstack1
            hstack2
        }.padding()
    }
    
    var hstack1: some View {
        HStack{
            Group{
                Triangle()
                    .stroke()
                Triangle()
                    .fill(Color.red)
                Triangle()
                    .stroke(Color.red, style: StrokeStyle(lineWidth: 10, lineCap: .round, lineJoin: .round))
                Arc(start: 110, end: 0, clockwise: true)
                    .stroke(lineWidth: 10)
                    .stroke(lineWidth: 5)
                    .stroke()
            }
            .frame(width: 100, height: 100)
            .border(Color.orange)
        }
    }
    
    var hstack2: some View {
        HStack{
            Group{
                Arc(start: 90, end: 0, clockwise: true)
                    .stroke(Color.blue, lineWidth: 20)
                Arc(start: 0, end: 270, clockwise: true)
                    .stroke(Color.pink, lineWidth: 8)
            }
            .frame(width: 208, height: 100)
            .border(Color.yellow)
        }
    }
}

PlaygroundPage.current.setLiveView(ContentView())
```
{% endtab %}

{% tab title="Arc" %}
```swift
import SwiftUI
import Vector2D    // for API: rect.center ...

struct Arc: Shape {
    
    var start: Double  // in degrees
    var end: Double    // in degrees
    var clockwise: Bool
    
    func path(in rect: CGRect) -> Path {
        Path { path in
            path.addArc(
                center: rect.center, 
                radius: rect.minSide / 2, 
                startAngle: .degrees(start), 
                endAngle: .degrees(end), 
                clockwise: !clockwise
            )
        }
    }
}
```
{% endtab %}

{% tab title="Triangle" %}
```swift
import SwiftUI
import Vector2D    // for API: rect.top ...

struct Triangle: Shape {
    func path(in rect: CGRect) -> Path { 
        Path { path in
            path.move(to: rect.top)
            path.addLine(to: rect.bottomLeft)
            path.addLine(to: rect.bottomRight)
            path.addLine(to: rect.top)
        }
    }
}
```
{% endtab %}

{% tab title="📘 手冊" %}
* [Shape](https://developer.apple.com/documentation/swiftui/shape) ⟩ [.path(in:)](https://developer.apple.com/documentation/swiftui/shape/path\(in:\))
{% endtab %}

{% tab title="👥 相關" %}
* [vector2d](../../custom/package/geometrykit/vector2d "mention")
{% endtab %}
{% endtabs %}

## 範例

* [💈 RoundedCorners](shape/roundedcorners)
