@FocusState — apa itu, kontrol fokus dan keyboard di SwiftUI

Penulis: IT Sectr Diterbitkan: 2026-06-26 Waktu membaca: 9 mnt

@FocusState — adalah property wrapper di SwiftUI, diperkenalkan di iOS 15, yang memungkinkan Anda mengontrol fokus input secara terprogram pada kolom teks dan elemen lainnya. Sebelum kemunculannya, pengembang harus menggunakan UIViewRepresentable untuk mengakses denganode UIKit becomeFirstResponder en resignFirstResponder. @FocusState memecahkan masalah ini secara native: u menghubungkan een properti aan veld via de .focused()-pengubah, setelah itu mengatur atau mereset fokus terjadi dengan menetapkan nilai. Menurut Apple Developer Documentation — FocusState (2025) mendukung @FocusState dua mode: Bool untuk kontrol sederhana (fokus ada atau tidak) dan enum untuk beberapa kolom, di mana setiap case sesuai dengan kolom input tertentu.

Utama

  • @FocusState — property wrapper untuk programmatisch focusbeheer di SwiftUI, tersedia sejak iOS 15.
  • Mode Bool — untuk één veld gunakan @FocusState var isFocused: Bool dengan .focused($isFocused).
  • Mode Enum — untuk meerdere velden gunakan enum dengan FocusStateValue-protocol en .focused($field, equals: .fieldName).
  • Sembunyikan keyboard — stel focus di op nil of false om toetsenbord te verbergen.
  • Fokus otomatis — stel de beginwaarde di di .onAppear om toetsenbord te tonen bij openen van scherm.

Apa itu @FocusState di SwiftUI

@FocusState — adalah property wrapper die de focusstatus menghubungkan dengan kolom input tertentu of een ander focusbaar element di SwiftUI. In tegenstelling tot UIKit, waar focusbeheer plaatsvindt via de denganhoden becomeFirstResponder en resignFirstResponder, gunakant SwiftUI een declaratieve benadering: u declareert de status (@FocusState) en menghubungkan deze aan element via de .focused()-pengubah. Het wijzigen van de status verandert automatisch de focus.

Voordat @FocusState di iOS 15 verscheen, moesten ontwikkelaars UIViewRepresentable-wrappers rond UITextField maken of bibliotheken van derden gunakanen. @FocusState is direct geïntegreerd di SwiftUI en werkt dengan TextField, TextEditor, SecureField en SearchField. Dit maakt de code schoner, vermindert aantal UIKit-bruggen en verbetert de testbaarheid.

Menurut WWDC Session 10136 — What's new di SwiftUI (2024) gunakant @FocusState SwiftUI-preference-sleutelsysteem om focusinformatie tussen elementen door te geven. Wanneer een veld focus ontvangt, werkt SwiftUI automatisch de gekoppelde @FocusState-properti bij, waardoor u kunt reageren op focuswijzigingen di de code.

Kontrol Fokus dengan Bool

De eenvoudigste manier om @FocusState te gunakanen — type Bool. Wanneer veld di focus is, is de properti true. Wanneer de focus verdwijnt — false. U kunt de focus geforceerd instellen door true toe te wijzen of resetten door false toe te wijzen.

swift
struct LoginForm: View {
    @State var email = ""
    @FocusState var isEmailFocused: Bool
    
    var body: some View {
        VStack {
            TextField("Email", text: $email)
                .focused($isEmailFocused)
            
            Button("Tampilkan Keyboard") {
                isEmailFocused = true
            }
            Button("Sembunyikan Keyboard") {
                isEmailFocused = false
            }
        }
    }
}

In dit untukbeeld wordt isEmailFocused automatisch true wanneer de gunakaner op tekstveld tikt, en false wanneer toetsenbord wordt verborgen. Knoppen maken programmatisch focusbeheer mogelijk — handig untuk kustom toetsenborden, „Volgende”-knoppen en situaties waardi toetsenbord na verzenden van een formulier geforceerd moet worden verborgen.

Kontrol Fokus dengan Enum untuk meerdere velden

Voor formulieren dengan meerdere velden mendukung @FocusState een enum die voldoet aan FocusStateValue-protocol (of Hashable). Elke case van de enum komt overeen dengan een specifiek veld. Hiermee kunt u de focus tussen velden beralih — bijuntukbeeld door op „Volgende” op toetsenbord te drukken om naar volgende veld te gaan.

swift
struct RegistrationForm: View {
    enum Field: Hashable {
        case email
        case password
        case confirmPassword
    }
    
    @State var email = ""
    @State var password = ""
    @State var confirmPassword = ""
    @FocusState var focusedField: Field?
    
    var body: some View {
        Form {
            TextField("Email", text: $email)
                .focused($focusedField, equals: .email)
                .onSubmit { focusedField = .password }
            
            SecureField("Password", text: $password)
                .focused($focusedField, equals: .password)
                .onSubmit { focusedField = .confirmPassword }
            
            SecureField("Confirm", text: $confirmPassword)
                .focused($focusedField, equals: .confirmPassword)
                .onSubmit { submitForm() }
        }
    }
}

Let op de .onSubmit-pengubah — deze dipanggil wanneer de gunakaner op „Return” op toetsenbord drukt. Di dalam .onSubmit beralih we focusedField naar volgende veld, wat automatisch de focus memindahkan. Het laatste veld roept submitForm() aan om formulier te verzenden.

Sembunyikan keyboard en tonen

@FocusState biedt een eenvoudige manier om toetsenbord te verbergen — stel de properti di op nil (untuk enum) of false (untuk Bool). Soms moet u echter toetsenbord verbergen zonder koppeling aan een specifiek veld — bijuntukbeeld bij tikken op een lege plek. In dit geval zijn er verschillende benaderingen.

swift
struct DismissKeyboardView: View {
    @State var text = ""
    @FocusState var isFocused: Bool
    
    var body: some View {
        TextField("Enter text", text: $text)
            .focused($isFocused)
            .toolbar {
                ToolbarItemGroup(placement: .keyboard) {
                    Spacer()
                    Button("Selesai") {
                        isFocused = false
                    }
                }
            }
    }
}

De .toolbar-pengubah dengan placement .keyboard voegt een knop boven toetsenbord toe. Dit is een standaard UX-patroon di iOS om toetsenbord te verbergen. Een alternatieve benadering — gunakan .onTapGesture op de root-VStack om de focus te resetten bij tikken op de achtergrond.

Fokus dan Validasi Formulir

@FocusState combineert uitstekend dengan formuliervalidatie. Het typische patroon: na indrukken van de knop „Verzenden” controleert u alle velden en stelt u de focus di op eerste veld dengan een fout. Dit verbetert de gunakanerservaring — de gunakaner ziet direct welk veld moet worden gecorrigeerd.

swift
struct ValidatedForm: View {
    enum Field: Hashable { case name; case phone }
    
    @State var name = ""
    @State var phone = ""
    @FocusState var focusedField: Field?
    @State var errors: [String] = []
    
    var body: some View {
        Form {
            TextField("Name", text: $name)
                .focused($focusedField, equals: .name)
            TextField("Phone", text: $phone)
                .focused($focusedField, equals: .phone)
            
            Button("Kirim") { validateAndSubmit() }
        }
    }
    
    func validateAndSubmit() {
        if name.isEmpty {
            focusedField = .name
            return
        }
        if phone.isEmpty {
            focusedField = .phone
            return
        }
        // kirim formulir
    }
}

In dit untukbeeld, wanneer veld name leeg is, memindahkan de focus zich ernaar en ziet de gunakaner direct waar de fout zit. Als name is ingevuld, wordt phone gecontroleerd. Dit is perilaku alami untuk formulieren — de gunakaner vult velden dari atas ke bawah di en de validatie volgt urutan yang sama.

Veeluntukkomende fouten dengan @FocusState

De meest untukkomende fout — proberen @FocusState te gunakanen dengan een type dat niet voldoet aan Hashable. @FocusState vereist dat type van de properti Hashable is (Bool en optionele enum voldoen al). Als u een kustom structuur probeert te gunakanen, zorg er dan untuk dat deze Hashable implementeert.

  • .focused()-pengubah vergeten — @FocusState beheert de focus niet zelf. U moet deze verplicht koppelen aan veld via .focused($property) of .focused($property, equals: .case).
  • Meerdere @FocusState di één View — untuk meerdere velden gunakant u één @FocusState dengan enum, niet meerdere @FocusState-propertipen. Meerdere Bool-propertipen worden niet onderling gesynchroniseerd.
  • @FocusState wijzigen buiten de madi thread — @FocusState mag alleen op de hoofdthread worden gewijzigd, net als alle UI-propertipen di SwiftUI. Asynchrone bewerkingen moeten overberalih naar MainActor untukdat ze worden gewijzigd.
  • Focus resetten bij herbouw — als de View wordt herbouwd, kan @FocusState worden gereset. Gebruik de .id()-pengubah untuk stabiele identificatie van de View.
swift
// ❌ Salah: dua @FocusState Bool bukan enum
@FocusState var isNameFocused: Bool
@FocusState var isEmailFocused: Bool

// ✅ Benar: satu enum @FocusState
enum Field: Hashable { case name; case email }
@FocusState var focusedField: Field?

Pertanyaan Umum

Vanaf welke iOS-versies is @FocusState beschikbaar?

@FocusState is tersedia sejak iOS 15, iPadOS 15, macOS 12, tvOS 15 en watchOS 8. Voor projecten die iOS 14 en lager ondersteunen, gunakant u UIViewRepresentable dengan UITextField en becomeFirstResponder, of bibliotheken van derden dengan een kustom implementatie van focusbeheer.

Kan @FocusState worden gunakant dengan kustom UIViewRepresentable?

Ja, hieruntuk moet u di de kustom UIViewRepresentable ondersteuning untuk FocusState implementeren via UIViewRepresentable-protocol. De kustom view moet becomeFirstResponder en resignFirstResponder hebben. SwiftUI menghubungkan @FocusState automatisch aan deze denganhoden als u de .focused()-pengubah opgeeft.

Waarom werkt @FocusState niet dengan TextField di List?

In List of Form kunnen cellen worden hergunakant, yang memutus hubungan van @FocusState dengan veld verbreekt. Solusi: tambahkan .id()-pengubah dengan een unieke identificatie toe untuk elke TextField. Bijuntukbeeld: .id(fieldName). Dit dwingt SwiftUI om een afzonderlijke View-instantie untuk elk veld te maken.

Hoe verberg ik toetsenbord bij tikken op een lege plek?

Voeg .onTapGesture toe aan de root-container (VStack, ZStack) en reset de focus: focusedField = nil. Echter, .onTapGesture kan tikken op knoppen binnendi blokkeren — gunakan een container dengan .contentShape(Rectangle()) en .onTapGesture erop, of een kustom UIKitBackgroundView.

Hoe animeer ik verschijnen van toetsenbord dengan @FocusState?

@FocusState biedt geen directe API untuk toetsenbordanimatie — dit is systeemgedrag van iOS. U kunt echter reageren op focuswijzigingen dengan .onChange(of: focusedField) of .onReceive(NotificationCenter.default.publisher(for: UIResponder.keyboardWillShowNotification)) untuk kustom animatie van de inhoud.

Ringkasan

  • @FocusState — property wrapper native SwiftUI untuk focusbeheer van invoer, tersedia sejak iOS 15.
  • Dua mode — Bool untuk één veld, Hashable enum untuk meerdere formuliervelden.
  • .focused()-pengubah — verplicht untuk koppelen van @FocusState dengan kolom input tertentu.
  • Kontrol terprogram — instellen van nil of false verbergt toetsenbord.
  • Validasi formulir — @FocusState maakt mogelijk om de focus di te stellen op eerste veld dengan een fout na controle.
  • Enum untuk meerdere velden — één @FocusState dengan enum heeft de untukkeur boven meerdere Bool-propertipen.
  • iOS 15+ — untuk oudere versies gunakant u UIViewRepresentable dengan becomeFirstResponder.

Kami akan mengembangkan aplikasi seluler turnkey

IT Sectr membuat aplikasi iOS dan Android untuk startup dan bisnis sejak 2017. Kami akan memberi saran dan mengusulkan solusi terbaik.

Diskusikan proyek

Baca juga