@FocusState, iOS 15'te tanıtılan SwiftUI'da bir property wrapper'dır ve metin alanları ile diğer öğelerde giriş odağını programlı olarak kontrol etmenizi sağlar. Ortaya çıkmasından önce, geliştiricilerin becomeFirstResponder ve resignFirstResponder UIKit yöntemlerine erişmek için UIViewRepresentable kullanması gerekiyordu. @FocusState bu sorunu yerel olarak çözer: .focused() değiştiricisi aracılığıyla bir özelliği bir alana bağlarsınız, ardından odağı ayarlama veya kaldırma basit bir değer atamasıyla gerçekleşir. Apple Developer Documentation — FocusState (2025)'e göre, @FocusState iki modu destekler: basit yönetim için Bool (odak açık veya kapalı) ve birden çok alan için enum, burada her bir case belirli bir giriş alanına karşılık gelir.
Önemli Noktalar
@FocusState, SwiftUI'da odak durumunu belirli bir giriş alanına veya diğer odaklanabilir öğeye bağlayan bir property wrapper'dır. Odak yönetiminin becomeFirstResponder ve resignFirstResponder yöntemleri aracılığıyla gerçekleştiği UIKit'in aksine, SwiftUI bildirimsel bir yaklaşım kullanır: bir durum (@FocusState) bildirir ve .focused() değiştiricisi aracılığıyla bir öğeye bağlarsınız. Durumu değiştirmek, odağı otomatik olarak değiştirir.
iOS 15'te @FocusState tanıtılmadan önce, geliştiricilerin UITextField çevresinde UIViewRepresentable sarmalayıcıları oluşturması veya üçüncü taraf kütüphaneleri kullanması gerekiyordu. @FocusState doğrudan SwiftUI'ya entegre edilmiştir ve TextField, TextEditor, SecureField ve SearchField ile çalışır. Bu, kodu daha temiz hale getirir, UIKit köprülerinin sayısını azaltır ve test edilebilirliği artırır.
WWDC Session 10136 — What's new in SwiftUI (2024)'e göre, @FocusState, öğeler arasında odak bilgisi iletmek için SwiftUI'nın preference key sistemini kullanır. Bir alan odak aldığında, SwiftUI ilişkili @FocusState özelliğini otomatik olarak günceller ve kod içinde odak değişikliklerine tepki vermenizi sağlar.
@FocusState kullanmanın en basit yolu Bool türüyledir. Bir alan odaklandığında, özellik true olur. Odak kaybedildiğinde — false. True olarak ayarlayarak odağı zorlayabilir veya false olarak ayarlayarak kaldırabilirsiniz.
struct LoginForm: View {
@State var email = ""
@FocusState var isEmailFocused: Bool
var body: some View {
VStack {
TextField("Email", text: $email)
.focused($isEmailFocused)
Button("Klavyeyi Göster") {
isEmailFocused = true
}
Button("Klavyeyi Gizle") {
isEmailFocused = false
}
}
}
}
Bu örnekte, isEmailFocused, kullanıcı metin alanına dokunduğunda otomatik olarak true olur ve klavye gizlendiğinde false olur. Düğmeler, odağı programlı olarak yönetmenize olanak tanır — özel klavyeler, "İleri" düğmeleri ve form gönderiminden sonra klavyeyi zorla gizlemeniz gereken durumlar için kullanışlıdır.
Birden çok alanı olan formlar için, @FocusState, FocusStateValue (veya Hashable) protokolüne uyan bir enum'ı destekler. Her bir enum case belirli bir alana karşılık gelir. Bu, alanlar arasında odağı değiştirmeye olanak tanır — örneğin, kullanıcı bir sonraki alana geçmek için klavyede "İleri" tuşuna bastığında.
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() }
}
}
}
.onSubmit değiştiricisine dikkat edin — kullanıcı klavyede "Return" tuşuna bastığında çağrılır. .onSubmit içinde focusedField'ı bir sonraki alana geçiririz, bu da odağı otomatik olarak taşır. Son alan, formu göndermek için submitForm()'u çağırır.
@FocusState, klavyeyi gizlemek için basit bir yol sağlar — özelliği nil (enum için) veya false (Bool için) olarak ayarlamanız yeterlidir. Ancak, bazen klavyeyi belirli bir alana bağlamadan gizlemeniz gerekebilir — örneğin, boş bir alana dokunduğunuzda. Bu durumda, birkaç yaklaşım vardır.
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("Tamam") {
isFocused = false
}
}
}
}
}
placement .keyboard ile .toolbar değiştiricisi, klavyenin üstüne bir düğme ekler. Bu, iOS'ta klavyeyi gizlemek için standart bir UX modelidir. Alternatif bir yaklaşım, arka plana dokunulduğunda odağı sıfırlamak için kök VStack üzerinde .onTapGesture kullanmaktır.
@FocusState, form doğrulama ile mükemmel bir şekilde birleşir. Tipik bir model: "Gönder" düğmesine bastıktan sonra, tüm alanları doğrulayın ve ilk hatalı alana odağı ayarlayın. Bu, kullanıcı deneyimini iyileştirir — kullanıcı hangi alanın düzeltilmesi gerektiğini hemen görür.
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("Gönder") { validateAndSubmit() }
}
}
func validateAndSubmit() {
if name.isEmpty {
focusedField = .name
return
}
if phone.isEmpty {
focusedField = .phone
return
}
// formu gönder
}
}
Bu örnekte, name alanı boşsa, odak ona taşınır ve kullanıcı hatanın nerede olduğunu hemen görür. name doldurulmuşsa, phone kontrol edilir. Bu, formlar için doğal bir davranıştır — kullanıcı alanları yukarıdan aşağıya doldurur ve doğrulama aynı sırayı takip eder.
En yaygın hata, Hashable'a uymayan bir türle @FocusState kullanmaya çalışmaktır. @FocusState, özellik türünün Hashable olmasını gerektirir (Bool ve isteğe bağlı enum'lar zaten uyar). Özel bir yapı kullanmaya çalışıyorsanız, Hashable'ı uyguladığından emin olun.
// ❌ Yanlış: enum yerine iki @FocusState Bool
@FocusState var isNameFocused: Bool
@FocusState var isEmailFocused: Bool
// ✅ Doğru: tek enum @FocusState
enum Field: Hashable { case name; case email }
@FocusState var focusedField: Field?
Sıkça Sorulan Sorular
@FocusState, iOS 15, iPadOS 15, macOS 12, tvOS 15 ve watchOS 8'den itibaren kullanılabilir. iOS 14 ve altını destekleyen projeler için, UITextField ve becomeFirstResponder ile UIViewRepresentable veya özel odak yönetimi uygulamasına sahip üçüncü taraf kütüphaneleri kullanın.
Evet, bunun için özel UIViewRepresentable içinde UIViewRepresentable protokolü aracılığıyla FocusState desteğini uygulamanız gerekir. Özel View, becomeFirstResponder ve resignFirstResponder'a sahip olmalıdır. .focused() değiştiricisini belirtirseniz SwiftUI, @FocusState'i bu yöntemlere otomatik olarak bağlayacaktır.
List veya Form'da hücreler yeniden kullanılabilir, bu da @FocusState'in alanla bağlantısını bozar. Çözüm: her TextField için benzersiz bir tanımlayıcıyla .id() değiştiricisini ekleyin. Örneğin: .id(fieldName). Bu, SwiftUI'nin her alan için ayrı bir View örneği oluşturmasını zorlar.
Kök kapsayıcıya (VStack, ZStack) .onTapGesture ekleyin ve odağı sıfırlayın: focusedField = nil. Ancak, .onTapGesture iç düğmelere dokunuşları engelleyebilir — .contentShape(Rectangle()) ile bir kapsayıcı ve üzerinde .onTapGesture kullanın veya özel bir UIKitBackgroundView kullanın.
@FocusState, klavye animasyonu için doğrudan bir API sağlamaz — bu iOS sistem davranışıdır. Ancak, özel içerik animasyonu için .onChange(of: focusedField) veya .onReceive(NotificationCenter.default.publisher(for: UIResponder.keyboardWillShowNotification)) ile odak değişikliklerine tepki verebilirsiniz.
Özet
Anahtar teslim bir mobil uygulama geliştireceğiz
IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.
Ayrıca okuyun