@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 — 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.
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.
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.
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.
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.
@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.
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.
@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.
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.
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.
// ❌ 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
@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.
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.
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.
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.
@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
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.
Baca juga