@FocusState — ano ito, pamamahala ng focus at keyboard sa SwiftUI

May-akda: IT Sectr Nai-publish: 2026-06-26 Oras ng pagbabasa: 9 min

@FocusState — adalah property wrapper sa SwiftUI, diperkenalkan sa iOS 15, na memungkinkan Anda mengontrol fokus input secara terprogram pada kolom teks at elemen lainnya. Sebelum kemunculannya, pengembang harus menggunakan UIViewRepresentable para sa 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 terjasa gamit ang menetapkan nilai. Menurut Apple Developer Documentation — FocusState (2025) mendukung @FocusState dua mode: Bool para sa kontrol sederhana (fokus ada atau tidak) at enum para sa beberapa kolom, sa mana setiap case sesuai gamit ang kolom input tertentu.

Utama

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

Apa itu @FocusState sa SwiftUI

@FocusState — adalah property wrapper die de focusstatus menghubungkan gamit ang kolom input tertentu of een ander focusbaar element sa 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 sa iOS 15 verscheen, moesten ontwikkelaars UIViewRepresentable-wrappers rond UITextField maken of bibliotheken van derden gunakanen. @FocusState is direct geïntegreerd sa SwiftUI en werkt gamit ang 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 sa 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 sa de code.

Kontrol Fokus gamit ang Bool

De eenvoudigste manier om @FocusState te gunakanen — type Bool. Wanneer veld sa 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("Ipakita ang Keyboard") {
                isEmailFocused = true
            }
            Button("Itago ang 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 para sa kustom toetsenborden, „Volgende”-knoppen en situaties waarsa toetsenbord na verzenden van een formulier geforceerd moet worden verborgen.

Kontrol Fokus gamit ang Enum para sa meerdere velden

Voor formulieren gamit ang meerdere velden mendukung @FocusState een enum die voldoet aan FocusStateValue-protocol (of Hashable). Elke case van de enum komt overeen gamit ang 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 sa op nil (para sa enum) of false (para sa 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("Tapos") {
                        isFocused = false
                    }
                }
            }
    }
}

De .toolbar-pengubah gamit ang placement .keyboard voegt een knop boven toetsenbord toe. Dit is een standaard UX-patroon sa 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 at Validasi Formulir

@FocusState combineert uitstekend gamit ang formuliervalidatie. Het typische patroon: na indrukken van de knop „Verzenden” controleert u alle velden en stelt u de focus sa op eerste veld gamit ang 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("Isumite") { validateAndSubmit() }
        }
    }
    
    func validateAndSubmit() {
        if name.isEmpty {
            focusedField = .name
            return
        }
        if phone.isEmpty {
            focusedField = .phone
            return
        }
        // isumite ang form
    }
}

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 para sa formulieren — de gunakaner vult velden dari atas ke bawah sa en de validatie volgt urutan na sama.

Veeluntukkomende fouten gamit ang @FocusState

De meest untukkomende fout — proberen @FocusState te gunakanen gamit ang 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 at para sa 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 sa één View — para sa meerdere velden gunakant u één @FocusState gamit ang enum, niet meerdere @FocusState-propertipen. Meerdere Bool-propertipen worden niet onderling gesynchroniseerd.
  • @FocusState wijzigen buiten de masa thread — @FocusState mag alleen op de hoofdthread worden gewijzigd, net als alle UI-propertipen sa 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 para sa stabiele identificatie van de View.
swift
// ❌ Mali: dalawang @FocusState Bool sa halip na enum
@FocusState var isNameFocused: Bool
@FocusState var isEmailFocused: Bool

// ✅ Tama: iisang 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 gamit ang UITextField en becomeFirstResponder, of bibliotheken van derden gamit ang een kustom implementatie van focusbeheer.

Kan @FocusState worden gunakant gamit ang kustom UIViewRepresentable?

Ja, hierpara sa moet u sa de kustom UIViewRepresentable ondersteuning para sa 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 gamit ang TextField sa List?

In List of Form kunnen cellen worden hergunakant, na memutus hubungan van @FocusState gamit ang veld verbreekt. Solusi: tambahkan .id()-pengubah gamit ang een unieke identificatie toe para sa elke TextField. Bijuntukbeeld: .id(fieldName). Dit dwingt SwiftUI om een afzonderlijke View-instantie para sa 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 binnensa blokkeren — gunakan een container gamit ang .contentShape(Rectangle()) en .onTapGesture erop, of een kustom UIKitBackgroundView.

Hoe animeer ik verschijnen van toetsenbord gamit ang @FocusState?

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

Ringkasan

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

Gagawa kami ng mobile application na turnkey

Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.

Pag-usapan ang proyekto

Basahin din