【SwiftUI】TextFieldビューを基本から学ぶ

# SwiftUIのテキストフィールド

TextFieldはコントロール系のSwiftUIビューです。
アプリケーションの画面に「文字列を編集する」ためのテキストフィールド・インターフェースを表示します。

> Swiftを基礎から学ぶには
自著、工学社より発売中の「[まるごと分かるSwiftプログラミング](https://amzn.asia/d/7YPWJwl)」をお勧めします。変数、関数、フロー制御構文、データ構造はもちろん、構造体からクロージャ、エクステンション、プロトコル、クロージャまでを基礎からわかりやすく解説しています。
> また、Swiftプログラミングを基礎から動画で学びたい方には、Udemyコース「[今日からはじめるプログラミング](https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=&cad=rja&uact=8&ved=2ahUKEwii1qTuj_2BAxV4hlYBHbj5BqEQFnoECBYQAQ&url=https%3A%2F%2Fwww.udemy.com%2Fcourse%2Fstart-programming-today%2F&usg=AOvVaw2vs4Sccq-bpfA4ZD2rCyNm&opi=89978449)」をお勧めします。

## TextFieldの概要

テキストフィールドには、ラベルと「ステート値のバインディング」が含まれます。
ステート値が文字列の場合、テキストフィールドはユーザー入力するに合わせて値を継続的に更新するか、フィールドのテキストを編集します。
ステート値が文字列ではない場合、ユーザーが（リターンキーを押すなどして）編集をコミットしたタイミングで、ステート値を更新します。

テキストフィールドのバインド値は、必ずしも文字列である必要はありません。
イニシャライザで`format`引数を指定すると、テキストフィールドを非文字列型の値にバインドできます。
そして、[FormatStyle](https://developer.apple.com/documentation/foundation/formatstyle)を使用して、入力されたテキストを「バインドされた型のインスタンス」に変換できます。

### テキストフィールドのプロンプト

テキストフィールドのプロンプトは、「入力すべきテキスト内容」をユーザーに示唆します。
テキストフィールドのプロンプトとラベルが「いつ、どこに表示されるか」は、各テキストフィールドのスタイルによって決定されます。
例えば、macOSのフォームでは、常にフィールド前端にラベルを配置し、プロンプトも利用可能な場合はフィールド自体のプレースホルダとして使用します。
iOSの同じ状況では、テキストフィールドのイニシャライザにプロンプトを指定した場合に、プロンプトをプレースホルダとして使用します。

下の画像は、2つのテキストフィールドを持つフォームの例です。
それぞれのフィールドが「Required」のプロンプトとラベルを提供します。

![スクリーンショット 2024-06-02 18.49.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/70476/89f3458b-5517-12bf-397c-ebef68dd4ec8.png)

```swift:フォーム内のテキストフィールド
Form {
    TextField(text: $username, prompt: Text("Required")) {
        Text("Username")
    }
    SecureField(text: $password, prompt: Text("Required")) {
        Text("Password")
    }
}
```

### テキストフィールドのスタイル

SwiftUIのテキストフィールドは、プラットフォームに最適化された外観と動作を反映した標準スタイルを提供します。
標準スタイルは、そのテキストフィールドが「特別なスタイルでテキストフィールドを表示するコンテナ内にあるか」も考慮します。
その上で、`textFieldStyle(_:)`モディファイアを使用すると、テキストフィールドの外観と操作性をカスタマイズして、`TextFieldStyle`のインスタンスを渡すことができます。

下の画像は、2つのテキストフィールドに`roundedBorder`スタイルを適用した例です。

![スクリーンショット 2024-06-02 18.50.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/70476/6e59bba4-138c-a1cf-1108-87abf6cecd55.png)

```swift: 境界線があるテキストフィールドのスタイル
VStack {
    TextField(
        "Given Name",
        text: $givenName
    )
    .disableAutocorrection(true)
    TextField(
        "Family Name",
        text: $familyName
    )
    .disableAutocorrection(true)
}
.textFieldStyle(.roundedBorder)
```

## コード

TextFieldビューは、テキストを入力できるボックスです。
テキストフィールドは、文字列のステート値を変更します。

### イニシャライザ

```swift
// テキストラベルを含むテキストフィールドを作成する（ラベルはテキスト）
init(
    _ titleKey: LocalizedStringKey,
    text: Binding<String>
)
```

```swift
// テキストラベルを含むテキストフィールドを作成する（ラベルはテキスト）
// promptは、ユーザーに「テキストフィールドで何を入力するか」を示すガイダンス
init(
    _ titleKey: LocalizedStringKey,
    text: Binding<String>,
    prompt: Text?
)
```

### 実践

![スクリーンショット 2024-06-02 23.29.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/70476/4938a4a0-30db-e4ac-ffd1-83e7cdb3be2d.png)

1. テキストフィールドで入力した文字列を格納するための、新しいステート変数を宣言します。

2. ビューの`body`に`TextField`を配置します。
`TextField`のイニシャライザでは、`text`引数にステート変数のバインディングを渡します。
これによって、`TextField`での入力でステート値が変更されると、SwiftUIはビューを更新します。

3. `.onSubmit`モディファイアでは、クロージャを使用して「ユーザーがリターンをタップしたときに実行するコードを指定します。
空の文字列が入力されないようにするには、if文を追加します。

4. テキストフィールドでキーボードのオートコレクトが不要な場合は、モディファイアを使用してオフにできます。

```swift
import SwiftUI

struct ContentView: View {
    @State private var message = ""
    
    var body: some View {
        VStack {
            TextField("あいさつをどうぞ", text: $message)
                .autocorrectionDisabled()
                .onSubmit {
                    if !message.isEmpty {
                        message = ""
                    }
                }
            Text(message)
                .font(.headline)
        }
        .padding()
    }
}
```

> iOSキーボードでテキストフィールドがどのように機能するかを確認するには、シミュレータで「Product > Run to run your app」を選択します。
場合によっては、テキストフィールドでのキーボードを表示するために、シミュレータで「I/O > Keyboard > Toggle Software Keyboard」を選択する必要があります。

## 参考

[Form](https://developer.apple.com/documentation/swiftui/form)
[TextField](https://developer.apple.com/documentation/swiftui/textfield)
[Develop in Swift Tutorials](https://developer.apple.com/tutorials/develop-in-swift/create-dynamic-content#Use-a-text-field-to-enter-names)