SwiftUIで画面遷移を実装する

## 環境
Xcode13.2.1
Swift 5.5.2

##基本的な画面遷移方法 
**1. NavigationLink**
**2. sheet**
**3. フラグによるViewの切り替え**

#1. NavigationLink
NavigationLinkはiOSの基本的なpush遷移になります。
以下のように実装します。

```swift
NavigationLink(destination: 遷移先のView) {
    任意のView（このViewをタップすると遷移先に指定したViewに遷移する）
}
```

##実装例
### Viewのタップで遷移する方法
NavigationLinkの末尾のクロージャに追加したViewをタップすることで遷移するやり方です。
追加したViewは最初からタップ可能になっています。

```swift
struct ContentView: View {
    var body: some View {
        NavigationView {
            NavigationLink(destination: SecondView()) {
                Text("画面遷移")
            }
        }
    }
}
```

**遷移元**
<img width="350" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/663839/ee0ca140-7a04-6cdc-88d3-27f8d3c7eb31.png">

**遷移先**
<img width="350" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/663839/e2d80052-191d-4bf8-f9b3-144678a9aa45.png">

:::note warn
NavigationLinkはNavigationView内に書いていないと画面遷移がされないので注意してください
:::

List表示でNavigationLinkを実装したい場合は以下のようにできます。

```swift
NavigationView {
    List {
        ForEach(users) { user in
            NavigationLink(destination: UserInfoView(user: user)) {
                Text(user.name)
            }
        }
    }
}
```

### isActiveで遷移を判定する方法
Viewを追加して遷移させる以外にも、NavigationLinkには`isActive`という引数を持っており、この値がtrueになった時に画面遷移が実行されます。

以下のコードは、ボタンをタップした時に`State変数`のshouldShowSecondViewをtrueにしています。
NavigationLinkのクロージャを`EmptyView()`とすることで、上記で説明していたようなタップで遷移させるためのViewは何も表示されません。

こちらの遷移方法は、何か処理が完了した後に画面遷移させたい場合などに使うことが多い思います。

```swift
struct ContentView: View {
    @State private var shouldShowSecondView: Bool = false
    
    var body: some View {
        NavigationView {
            VStack {
                NavigationLink(destination: SecondView(), isActive: $shouldShowSecondView) {
                    EmptyView()
                }
                
                Button {
                    shouldShowSecondView = true
                } label: {
                    Text("フラグ切替")
                }
            }
        }
    }
}
```

###遷移元に戻る方法
NavigationLinkでの画面遷移は自動的に遷移先に戻るボタンが表示されます。
戻るボタンを使わないコードでの実装は、環境変数`dismiss`を使用します。

```swift
struct SecondView: View {
    @Environment(\.dismiss) var dismiss
    
    var body: some View {
        Button {
            // 任意の場所で呼ぶ 
            dismiss()
        } label: {
            Text("シートを閉じる")
        }
    }
}
```

#2. sheet
sheetは下からViewが表示されるモーダル表示です。

```swift
.sheet(isPresented: Binding<Bool>), onDismiss: (() -> Void)? = nil) {
    遷移先のView
}
```

**引数**
**isPresented**
ここに指定した変数がtrueの時に遷移先のViewがモーダル表示されます。

**onDismiss**
シートが閉じる時に実行されるクロージャです。何も処理がない場合は定義する必要はありません

##実装例
```swift
struct ContentView: View {
    // 表示フラグ
    @State private var isShowingView: Bool = false
    
    var body: some View {
        Button {
            isShowingView.toggle()
        } label: {
            Text("シート")
        }
        .sheet(isPresented: $isShowingView) {
            SecondView()
        }
    }
}
```

**遷移元**
<img width="350" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/663839/2ff30516-8669-25c3-645c-b1250110b7de.png">

**遷移先**
<img width="350" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/663839/9cf28ddf-d29d-69ac-1668-2bbc2cbffa0a.png">

Buttonに`sheet`を定義して、タップ処理に`isPresented`のフラグを変更する処理を実装しています。
このようにすることでボタンが押された時にtrueになるのでシートが表示されるようになります。

表示フラグに使用する変数は、値の変更を監視できるように`@State`を付けた変数である必要があります。そのため引数の`isPresented`に定義する際は`$`を付与します。

```swift
@State private var isShowingView: Bool = false
```

###遷移元に戻る方法
- 下にスワイプしてシートを閉じる
- dismissハンドラーを実行する

dismissハンドラーはNavigationLinkの戻る実装と同じになります。

#3. フラグによるViewの切り替え
`NavigationLink`などの画面遷移メソッドは使わずにフラグを用いてViewを出し分ける方法です。
瞬時にViewが表示されるので、アニメーションを付けたい場合は別途実装する必要があります。

##実装例
```swift
struct ContentView: View {
    @State private var isShowingView: Bool = false
    
    var body: some View {
        if isShowingView {
            SecondView()
        } else {
            Button {
                isShowingView.toggle()
            } label: {
                Text("フラグ切替")
            }
        }
    }
}
```

今回はSwiftUIの基本的な画面遷移方法についてまとめました。