SwiftUI完全に理解した

@Yametaro さんメインで定期開催していた #ゆめみからの挑戦状 ですが、今回は私から SwiftUI に関連する問題として出題させていただきました。

# 問題

https://twitter.com/yumemiinc/status/1587286811855925248

```swift
import SwiftUI

@main
struct MyApp: App {
    var body: some Scene {
        WindowGroup {
            Text("SwiftUI\n完全に理解した")
                /* ここに解答を書いてください */
        }
    }
}
```

どこかで見たような話ですが、SwiftUIの可能性に挑む問題として出題しました。

## 解答例

![顧客が説明した要件](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228438/47e328be-4501-359a-97d3-031720b11bcf.png)

```swift
import SwiftUI

@main
struct MyApp: App {
    var body: some Scene {
        WindowGroup {
            Text("SwiftUI\n完全に理解した")
                // 回答
                .padding()
                .offset(x: 50, y: 0)
                .overlay(
                    RoundedRectangle(cornerRadius: 16)
                        .stroke(Color.black, lineWidth: 2)
                )
        }
    }
}
```

# 解説

## 角丸の枠線

みんな大好き、角丸の枠線です

### `cornerRadius`

枠線(border)に角丸(cornerRadius)をつければいいんだろ、と思ってやってみると失敗します

```swift
import SwiftUI

@main
struct MyApp: App {
    var body: some Scene {
        WindowGroup {
            Text("SwiftUI\n完全に理解した")
                .padding()
                .border(.black, width: 2)
                .cornerRadius(16)
        }
    }
}
```
![プロジェクトリーダーの理解](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228438/3cdba2ca-b0a7-5ac1-9c79-413ee811eb32.png)

`cornerRadius` はviewをclipしますので、枠線をつけたviewが角丸でclipされてしまいます

> Clips this view to its bounding frame, with the specified corner radius.

https://developer.apple.com/documentation/swiftui/view/cornerradius(_:antialiased:)

#### cornerRadiusを使って角丸枠線を書く事もできます

![アナリストのデザイン](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228438/3ae24f47-d1cc-fed5-0d8c-b8a9390253d9.png)

```swift
import SwiftUI

@main
struct MyApp: App {
    var body: some Scene {
        WindowGroup {
            Text("SwiftUI\n完全に理解した")
                .padding()
                .background(.white)
                .cornerRadius(12)
                .padding(4)
                .background(.black)
                .cornerRadius(16)
        }
    }
}
```

しかし、この方法で完全に理解してしまうと、はみ出した部分がClipされてしまいますね

![実装された運用](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228438/a03ea889-5d90-300b-33cc-2ce12641644f.png)

### overlay

`overlay` を使うとViewの上に別のViewを重ねる事ができます

https://developer.apple.com/documentation/swiftui/view/overlay(alignment:content:)

今回は組み込み図形の中から RoundedRectangle をのせました

https://developer.apple.com/documentation/swiftui/roundedrectangle

また、 `stroke` で Shape の輪郭のみ描画をしています

https://developer.apple.com/documentation/swiftui/shape/stroke(linewidth:)

## 完全に理解する

位置の指定は `offset` を使います

https://developer.apple.com/documentation/swiftui/view/offset(x:y:)

ちょっと右に寄せてと言われたのでしょうか、その場合はoffsetを付ける位置を変えるとよさそうです

![顧客が本当に必要だったもの](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228438/28b916ea-eba3-8bd1-8664-0acd03106a22.png)

```swift
import SwiftUI

@main
struct MyApp: App {
    var body: some Scene {
        WindowGroup {
            Text("SwiftUI\n完全に理解した")
                .padding()
                .overlay(alignment: .trailing) {
                    RoundedRectangle(cornerRadius: 16)
                        .stroke(Color.black, lineWidth: 2)
                }
                .offset(x: 40, y: 0)
        }
    }
}
```

---

# みんなの解答

## 正統派

数字に多少ばらつきはありますが、正解ですね

https://twitter.com/SchroSis/status/1587344516423421952?s=20&t=2pccOCDCMruqgYCeiKL1BA

https://twitter.com/zunda_pixel/status/1587370401524764672?s=20&t=2pccOCDCMruqgYCeiKL1BA

https://twitter.com/rikinyan_nonail/status/1588210500256817152?s=20&t=2pccOCDCMruqgYCeiKL1BA

https://twitter.com/SNQ2001/status/1588913683841060864?s=20&t=2pccOCDCMruqgYCeiKL1BA

## ベジェ曲線

角丸枠線をベジェ曲線で描いてくれました
Pathを使う事で複雑な図形も対応できますね

https://developer.apple.com/documentation/swiftui/path

https://twitter.com/mitsuharu_e/status/1587936803897548804

流行りにのったこちらの解答もいただいています

https://twitter.com/mitsuharu_e/status/1590285888533463042

## アニメーション

手作りのアニメーションをつけてくれました

https://twitter.com/kazu725140/status/1588102328552300544

## 番外編

https://twitter.com/auramagi/status/1587748749673041920

### 1. Fake

base64Encodeで画像を読み込んで表示しています

### 2. Replace

一度、`opacity(0)`で非表示にしてから`HStack`と`Color.clear.frame`でずらしています

### 3. Reframe

`fixedSize`でサイズを固定した後に`frame`を使ってずらしています

色をつけてやるとちょっとわかりやすくなりそうです

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228438/c880bbd0-3b32-9376-9afc-60968f72e52e.png)

```swift
import SwiftUI

@main
struct MyApp: App {

    var body: some Scene {
        WindowGroup {
            Text("SwiftUI\n完全に理解した")
                .fixedSize()
                .background(Color.yellow.opacity(0.7))
                .frame(width: 32)
                .border(Color.red)
                .frame(width: 111, alignment: .trailing)
                .background(Color.blue.opacity(0.7))
                .padding()
                .overlay(alignment: .trailing) {
                    RoundedRectangle(cornerRadius: 16)
                        .stroke(Color.black, lineWidth: 2)
                }
        }
    }
}
```

### 4. Realign

`alignmentGuide`を使って、centerをずらしています

# 感想

解答ありがとうございました
軽い気持ちで出したお題でしたが、さまざまな解答をいただきました

SwiftUIの自由さや、表現力の高さ、読みやすさなどを感じてもらえたら幸いです
SwiftUIは書いていて楽しいので、皆様もぜひ挑戦してみてください