【SwiftUI 3.0】TextField のフォーカスを管理する方法

SwiftUI 3.0 で @FocusState と言うフォーカス対象を管理する状態変数が追加されたので試してみました。

動作確認環境

macOS Monterey 12.1

Xcode 13.2.1

iOS 15.2(iPhone SE(2nd Generation)シミュレータ)

【SwiftUI 3.0】TextField のフォーカスを管理する方法

設定手順

対象のTextFieldをenumで定義

管理対象となる TextField を識別するために下記のような enum を定義します。

enum FocusTextFields {
    case email
    case password
}
@FocusState 変数の宣言

enum で定義した型の @FocusState 変数を用意します。

@FocusState var focusState: FocusTextFields?
.focused プロパティで TextField に紐付ける

@FocusState 変数と enum を .focused プロパティでTextFieldに紐付けます。

TextField("Email", text: $emailText)
    .focused($focusState, equals: .email)

以上のような設定をするだけで、@FocusState で宣言した変数の値を変更することでフォーカス先を移動することができるようになります。

サンプルコード

冒頭のgif動画の全体コードは以下の通りです。

Button を押下した時にそれぞれの TextField にフォーカスを移しています。

struct ContentView: View {
    
    enum FocusTextFields {
        case email
        case password
    }
    @FocusState private var focusState: FocusTextFields?
    
    @State private var emailText = ""
    @State private var passwordText = ""
    
    var body: some View {
        VStack {
            TextField("Email", text: $emailText)
                .focused($focusState, equals: .email)
            SecureField("Password", text: $passwordText)
                .focused($focusState, equals: .password)
            VStack {
                Button("Focus Email", action: {
                    focusState = .email
                })
                Button("Focus Password", action: {
                    focusState = .password
                })
            }
        }
        .padding()
        .textFieldStyle(.roundedBorder)
    }
}

画面表示時にフォーカスするには?

@FocusState 変数に初期値を与えようとするとビルドエラーとなってしまいます。

そのため、画面表示タイミングで任意の TextField にフォーカスを当てるには onAppear でセットする必要があります

但し注意点として、onAppear が呼ばれてから少し間を置かないとうまくフォーカスしてくれないようなので、以下のようにすると良いでしょう。

.onAppear {
    DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
        focusState = .password
    }
}

以上