【SwiftUI】alertメソッドでアラートを出す

先日リリースした私のアプリに使用した技術をひとつずつ解説しています。
私のアプリはこちら。

https://apps.apple.com/jp/app/id1553876980

# alertとは

下のようなアラートを出すメソッド。iPhoneを使っているといろんな場面で見かけるかと思います。

![スクリーンショット 2021-03-01 15.37.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1130636/0003a64e-54c1-cc07-8ce5-6ff2448b6c05.png)


https://developer.apple.com/documentation/swiftui/view/alert(ispresented:content:)

# 実際の動作

<iframe width="560" height="315" src="https://www.youtube.com/embed/Hf2WgrmS6Qk" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

このように、ボタンを押すとアラートが出るサンプルアプリを作りました。こちらについて解説します。

# 基本的な書き方

まず、alertメソッドの基本的な書き方を説明します。

```Swift:alertメソッド
.alert(isPresented: ブール値, content: { Alert(アラートの内容) })
```

引数の```isPresented```がtrueになったときにアラートが出現します。
アラートの内容は```content```に書き、```Alert構造体```を使います。

サンプルアプリのコードについて解説します。

# ソースコード

https://github.com/masayoshi0327/Alert

```Swift:ContentView.swift
import SwiftUI

struct ContentView: View {
    @State var goodAlert = false //いいね！ボタンの方のアラートを出すためのブール値
    @State var isGood = false //サムズアップに色をつけるかどうかのブール値
    @State var noGoodAlert = false //よくないね！ボタンの方のアラートを出すためのブール値
    
    var body: some View {
        VStack{
            // サムズアップのマーク。isGoodがtrueになると色がつく。
            Image(systemName: isGood ? "hand.thumbsup.fill":"hand.thumbsup")
                .font(.title)
                .foregroundColor(isGood ? .pink:.none)
                .padding()
            // いいね！ボタン
            Button(action: {
                goodAlert = true // このアクションでアラートを呼び出す
            }, label: {
                buttonLabel(text: "いいね！", fieldColor: Color.pink)
            })
                .padding()
                // goodAlertがtrueになると呼び出されるアラート
                .alert(isPresented: $goodAlert, content: {
                    Alert(
                        title: Text("いいね！しますか？"),
                        message: Text("いいね！すると色がつきます。"),
                        primaryButton: .default(Text("はい"),
                                                action: {isGood = true}),
                        secondaryButton: .destructive(Text("いいえ"),
                                                      action: {isGood = false})
                    )
                })
            // よくないね！ボタン
            Button(action: {
                noGoodAlert = true // このアクションでアラートを呼び出す
            }, label: {
                buttonLabel(text: "よくないね！", fieldColor: Color.blue)
            })
                .padding()
                // noGoodAlertがtrueになると呼び出されるアラート
                .alert(isPresented: $noGoodAlert, content: {
                    Alert(title: Text("そんなこと言わないで"))
                })
        }
    }
}

struct buttonLabel: View {
    let text: String
    let fieldColor: Color
    
    var body: some View {
        Text(text)
            .font(.title)
            .foregroundColor(.white)
            .frame(width: 250, height: 100)
            .background(fieldColor)
            .cornerRadius(30)
    }
}

```

全体のソースコードはこのようになっています。
少し複雑なので、いいね！ボタンの方に焦点を当てて説明したいと思います。

# いいね！ボタンとアラートの仕組み

まず、ContentViewのプロパティとしてブール型の変数を用意しています。

```Swift
    @State var goodAlert = false //いいね！ボタンの方のアラートを出すためのブール値
    @State var isGood = false //サムズアップに色をつけるかどうかのブール値
```

いいね！ボタンのアラートを出すための変数```goodAlert```は初期値としてfalseを入れています。初期値がtrueの場合、アプリ起動時にアラートが表示されることになります。

次に、```goodAlert```がtrueに反転するためのトリガーを書きます。

```Swift
            Button(action: {
                goodAlert = true // このアクションでアラートを呼び出す
            }, label: {
                buttonLabel(text: "いいね！", fieldColor: Color.pink)
            })
```

今回はボタンのアクションによってアラートを呼び出したいので、このようになります。

そして、呼び出すアラートがこちら。

```Swift
                .alert(isPresented: $goodAlert, content: {
                    Alert(
                        title: Text("いいね！しますか？"),
                        message: Text("いいね！すると色がつきます。"),
                        primaryButton: .default(Text("はい"),
                                                action: {isGood = true}),
                        secondaryButton: .destructive(Text("いいえ"),
                                                      action: {isGood = false})
                    )
                })
```

　```isPresented```にgoodAlertを入れているので、goodAlertがtrueに反転したときに```content```に書かれているアラートが出現します。

このように書くことで出現するアラートがこちらです。

![スクリーンショット 2021-03-01 15.37.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1130636/0003a64e-54c1-cc07-8ce5-6ff2448b6c05.png)

こうして見ると、Alert構造体のどの引数がどの部分に表れているかわかりやすいかと思います。このアラートの「はい」ボタンを押すことで```isGood```にtrueが、「いいえ」ボタンを押すことでfalseが入ります。そうすることで結果的にサムズアップのマークに色がついたり消えたりしているのです。

# よくないね！ボタンとアラートの仕組み

次に、よくないね！ボタンの方の説明をしていきます。
こちらもまずはブール型の変数を用意しています。

```Swift
    @State var noGoodAlert = false //よくないね！ボタンの方のアラートを出すためのブール値
```

こちらの変数を反転させるトリガーがこちら。

```Swift
            Button(action: {
                noGoodAlert = true // このアクションでアラートを呼び出す
            }, label: {
                buttonLabel(text: "よくないね！", fieldColor: Color.blue)
            })
```

呼び出すアラートはこちら。

```Swift
                .alert(isPresented: $noGoodAlert, content: {
                    Alert(title: Text("そんなこと言わないで"))
                })
```

いいね！ボタンの方のアラートに比べるとすっきりしています。実は、__Alert構造体はtitleさえあればアラートとして機能します__。

実際に出現するアラートがこちら。

![スクリーンショット 2021-03-01 17.18.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1130636/4a12f61b-a734-c928-626a-c24d08bba16d.png)

Alert構造体にはタイトルしか書いていませんが、自動的にOKボタンをつけてくれます。__このボタンを押すと```isPresented```がfalseになり、アラートが消えます__。(いいね！ボタンの方も同様の仕組みでアラートが消えています)

# アラートのボタンについて

先ほど述べたように、Alert構造体はtitleがあれば機能し、アラートを消すボタンを自動的につけてくれますが、どのようなボタンにするかを指定することができます。

アラートのボタンはひとつ、もしくはふたつ付けることができます。それぞれ使用する引数が違うので、別々に解説したいと思います。

## ボタンがひとつの場合

先ほどのよくないね！アラートを次のように書きかえます。

```Swift
                .alert(isPresented: $noGoodAlert, content: {
                    Alert(title: Text("そんなこと言わないで"),
                          dismissButton: .default(Text("了解です")))
                })
```

`dismissButton`という引数を追加しました。これによりボタンのテキストが変わります。

![スクリーンショット 2021-03-01 17.45.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1130636/6c6f476c-94b5-5a7f-65d3-87c4651a8651.png)

「了解です」ボタンを押すとアラートが消えてくれます。このボタンに機能を追加したい場合、`.default`の引数の`action`に書けば追加できます。

## ボタンがふたつの場合

いいね！のアラートをもう一度見てみましょう。

```Swift
                .alert(isPresented: $goodAlert, content: {
                    Alert(
                        title: Text("いいね！しますか？"),
                        message: Text("いいね！すると色がつきます。"),
                        primaryButton: .default(Text("はい"),
                                                action: {isGood = true}),
                        secondaryButton: .destructive(Text("いいえ"),
                                                      action: {isGood = false})
                    )
                })
```

`primaryButton`がボタンひとつめ、`secondaryButton`がふたつめです（そのままですね）。
primaryButtonでは`.default`、secondaryButtonでは`.destructive`というメソッドが使われています。実はこれらが__ボタンの文字の色__を決めています。

![スクリーンショット 2021-03-01 15.37.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1130636/0003a64e-54c1-cc07-8ce5-6ff2448b6c05.png)

「はい」ボタンの方はdefault、つまりデフォルトの色の青になります。destructiveとは__「破壊的な」__という意味があり、これを使った「いいえ」ボタンは文字が__赤色__になっています。これらふたつを使い分けることで、__ユーザーの押し間違いを減らす効果__が期待できます。ぜひ使い分けましょう。

# まとめ

alertメソッドはおそらく、iPhoneを触っていれば見ない日はないほど頻繁に見る機能かと思います。使うシーンもさまざまなので、ぜひこの機能を応用してアプリに取り入れてみてください。