@FocusState — wat is het, focus- en toetsenbordbeheer in SwiftUI

Auteur: IT Sectr Gepubliceerd: 2026-06-26 Leestijd: 9 min

@FocusState — is een property wrapper in SwiftUI, geïntroduceerd in iOS 15, waarmee u programmatisch de invoerfocus op tekstvelden en andere elementen kunt beheren. Voordat het verscheen, moesten ontwikkelaars UIViewRepresentable gebruiken om toegang te krijgen tot de UIKit-methoden becomeFirstResponder en resignFirstResponder. @FocusState lost dit probleem op een native manier op: u koppelt een eigenschap aan het veld via de .focused()-modifier, waarna het instellen of resetten van de focus plaatsvindt door simpelweg een waarde toe te wijzen. Volgens Apple Developer Documentation — FocusState (2025) ondersteunt @FocusState twee modi: Bool voor eenvoudig beheer (focus is er of niet) en enum voor meerdere velden, waarbij elke case overeenkomt met een specifiek invoerveld.

Belangrijkste

  • @FocusState — property wrapper voor programmatisch focusbeheer in SwiftUI, beschikbaar vanaf iOS 15.
  • Bool-modus — voor één veld gebruik @FocusState var isFocused: Bool met .focused($isFocused).
  • Enum-modus — voor meerdere velden gebruik enum met het FocusStateValue-protocol en .focused($field, equals: .fieldName).
  • Toetsenbord verbergen — stel focus in op nil of false om het toetsenbord te verbergen.
  • Automatische focus — stel de beginwaarde in in .onAppear om het toetsenbord te tonen bij het openen van het scherm.

Wat is @FocusState in SwiftUI

@FocusState — is een property wrapper die de focusstatus koppelt aan een specifiek invoerveld of een ander focusbaar element in SwiftUI. In tegenstelling tot UIKit, waar focusbeheer plaatsvindt via de methoden becomeFirstResponder en resignFirstResponder, gebruikt SwiftUI een declaratieve benadering: u declareert de status (@FocusState) en koppelt deze aan het element via de .focused()-modifier. Het wijzigen van de status verandert automatisch de focus.

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

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

Focus beheren met Bool

De eenvoudigste manier om @FocusState te gebruiken — het type Bool. Wanneer het veld in focus is, is de eigenschap 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("Toetsenbord tonen") {
                isEmailFocused = true
            }
            Button("Toetsenbord verbergen") {
                isEmailFocused = false
            }
        }
    }
}

In dit voorbeeld wordt isEmailFocused automatisch true wanneer de gebruiker op het tekstveld tikt, en false wanneer het toetsenbord wordt verborgen. Knoppen maken programmatisch focusbeheer mogelijk — handig voor aangepaste toetsenborden, „Volgende”-knoppen en situaties waarin het toetsenbord na het verzenden van een formulier geforceerd moet worden verborgen.

Focus beheren met Enum voor meerdere velden

Voor formulieren met meerdere velden ondersteunt @FocusState een enum die voldoet aan het FocusStateValue-protocol (of Hashable). Elke case van de enum komt overeen met een specifiek veld. Hiermee kunt u de focus tussen velden schakelen — bijvoorbeeld door op „Volgende” op het toetsenbord te drukken om naar het 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-modifier — deze wordt aangeroepen wanneer de gebruiker op „Return” op het toetsenbord drukt. Binnen .onSubmit schakelen we focusedField naar het volgende veld, wat automatisch de focus verplaatst. Het laatste veld roept submitForm() aan om het formulier te verzenden.

Toetsenbord verbergen en tonen

@FocusState biedt een eenvoudige manier om het toetsenbord te verbergen — stel de eigenschap in op nil (voor enum) of false (voor Bool). Soms moet u echter het toetsenbord verbergen zonder koppeling aan een specifiek veld — bijvoorbeeld bij het 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("Gereed") {
                        isFocused = false
                    }
                }
            }
    }
}

De .toolbar-modifier met placement .keyboard voegt een knop boven het toetsenbord toe. Dit is een standaard UX-patroon in iOS om het toetsenbord te verbergen. Een alternatieve benadering — gebruik .onTapGesture op de root-VStack om de focus te resetten bij het tikken op de achtergrond.

Focus en formuliervalidatie

@FocusState combineert uitstekend met formuliervalidatie. Het typische patroon: na het indrukken van de knop „Verzenden” controleert u alle velden en stelt u de focus in op het eerste veld met een fout. Dit verbetert de gebruikerservaring — de gebruiker 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("Verzenden") { validateAndSubmit() }
        }
    }
    
    func validateAndSubmit() {
        if name.isEmpty {
            focusedField = .name
            return
        }
        if phone.isEmpty {
            focusedField = .phone
            return
        }
        // formulier verzenden
    }
}

In dit voorbeeld, wanneer het veld name leeg is, verplaatst de focus zich ernaar en ziet de gebruiker direct waar de fout zit. Als name is ingevuld, wordt phone gecontroleerd. Dit is natuurlijk gedrag voor formulieren — de gebruiker vult velden van boven naar beneden in en de validatie volgt dezelfde volgorde.

Veelvoorkomende fouten met @FocusState

De meest voorkomende fout — proberen @FocusState te gebruiken met een type dat niet voldoet aan Hashable. @FocusState vereist dat het type van de eigenschap Hashable is (Bool en optionele enum voldoen al). Als u een aangepaste structuur probeert te gebruiken, zorg er dan voor dat deze Hashable implementeert.

  • .focused()-modifier vergeten — @FocusState beheert de focus niet zelf. U moet deze verplicht koppelen aan het veld via .focused($property) of .focused($property, equals: .case).
  • Meerdere @FocusState in één View — voor meerdere velden gebruikt u één @FocusState met enum, niet meerdere @FocusState-eigenschappen. Meerdere Bool-eigenschappen worden niet onderling gesynchroniseerd.
  • @FocusState wijzigen buiten de main thread — @FocusState mag alleen op de hoofdthread worden gewijzigd, net als alle UI-eigenschappen in SwiftUI. Asynchrone bewerkingen moeten overschakelen naar MainActor voordat ze worden gewijzigd.
  • Focus resetten bij herbouw — als de View wordt herbouwd, kan @FocusState worden gereset. Gebruik de .id()-modifier voor stabiele identificatie van de View.
swift
// ❌ Fout: twee @FocusState Bool in plaats van enum
@FocusState var isNameFocused: Bool
@FocusState var isEmailFocused: Bool

// ✅ Juist: één enum @FocusState
enum Field: Hashable { case name; case email }
@FocusState var focusedField: Field?

Veelgestelde vragen

Vanaf welke iOS-versies is @FocusState beschikbaar?

@FocusState is beschikbaar vanaf iOS 15, iPadOS 15, macOS 12, tvOS 15 en watchOS 8. Voor projecten die iOS 14 en lager ondersteunen, gebruikt u UIViewRepresentable met UITextField en becomeFirstResponder, of bibliotheken van derden met een aangepaste implementatie van focusbeheer.

Kan @FocusState worden gebruikt met aangepaste UIViewRepresentable?

Ja, hiervoor moet u in de aangepaste UIViewRepresentable ondersteuning voor FocusState implementeren via het UIViewRepresentable-protocol. De aangepaste view moet becomeFirstResponder en resignFirstResponder hebben. SwiftUI koppelt @FocusState automatisch aan deze methoden als u de .focused()-modifier opgeeft.

Waarom werkt @FocusState niet met TextField in List?

In List of Form kunnen cellen worden hergebruikt, wat de koppeling van @FocusState met het veld verbreekt. Oplossing: voeg de .id()-modifier met een unieke identificatie toe voor elke TextField. Bijvoorbeeld: .id(fieldName). Dit dwingt SwiftUI om een afzonderlijke View-instantie voor elk veld te maken.

Hoe verberg ik het toetsenbord bij het 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 binnenin blokkeren — gebruik een container met .contentShape(Rectangle()) en .onTapGesture erop, of een aangepaste UIKitBackgroundView.

Hoe animeer ik het verschijnen van het toetsenbord met @FocusState?

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

Samenvatting

  • @FocusState — native SwiftUI property wrapper voor focusbeheer van invoer, beschikbaar vanaf iOS 15.
  • Twee modi — Bool voor één veld, Hashable enum voor meerdere formuliervelden.
  • .focused()-modifier — verplicht voor het koppelen van @FocusState aan een specifiek invoerveld.
  • Programmatisch beheer — instellen van nil of false verbergt het toetsenbord.
  • Formuliervalidatie — @FocusState maakt het mogelijk om de focus in te stellen op het eerste veld met een fout na controle.
  • Enum voor meerdere velden — één @FocusState met enum heeft de voorkeur boven meerdere Bool-eigenschappen.
  • iOS 15+ — voor oudere versies gebruikt u UIViewRepresentable met becomeFirstResponder.

We ontwikkelen een mobiele applicatie turnkey

IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.

Bespreek het project

Lees ook