@FocusState — nedir, SwiftUI'da odak ve klavye yönetimi

Yazar: IT Sectr Yayınlanma: 2026-06-26 Okuma süresi: 9 dk

@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 programlı odak yönetimi için bir property wrapper, iOS 15'ten itibaren kullanılabilir.
  • Bool Modu — tek bir alan için .focused($isFocused) ile @FocusState var isFocused: Bool kullanın.
  • Enum Modu — birden çok alan için FocusStateValue protokolüne uyan bir enum ve .focused($field, equals: .fieldName) kullanın.
  • Klavyeyi Gizleme — klavyeyi gizlemek için odağı nil veya false olarak ayarlayın.
  • Otomatik Odak — ekran açıldığında klavyeyi göstermek için .onAppear içinde başlangıç değerini ayarlayın.

SwiftUI'da @FocusState Nedir

@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.

Bool ile Odak Yönetimi

@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.

swift
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 için Enum ile Odak Yönetimi

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.

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() }
        }
    }
}

.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.

Klavyeyi Gizleme ve Gösterme

@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.

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("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.

Odak ve Form Doğrulama

@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.

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("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.

@FocusState ile Sık Yapılan Hatalar

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.

  • .focused() değiştiricisi unutuldu — @FocusState tek başına odağı yönetmez. .focused($property) veya .focused($property, equals: .case) aracılığıyla bir alana bağlanması zorunludur.
  • Bir View'da birden çok @FocusState — birden çok alan için, birden çok @FocusState özelliği yerine enum ile tek bir @FocusState kullanın. Birden çok Bool özelliği birbiriyle senkronize olmaz.
  • @FocusState'i ana iş parçacığı dışında değiştirme — @FocusState, SwiftUI'daki tüm UI özellikleri gibi yalnızca ana iş parçacığında değiştirilmelidir. Zaman uyumsuz işlemler, değiştirmeden önce MainActor'a geçmelidir.
  • View yeniden oluşturulduğunda odak sıfırlanması — View yeniden oluşturulursa, @FocusState sıfırlanabilir. Kararlı View tanımlaması için .id() değiştiricisini kullanın.
swift
// ❌ 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 hangi iOS sürümlerinden itibaren kullanılabilir?

@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.

@FocusState özel UIViewRepresentable ile kullanılabilir mi?

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.

@FocusState, List içindeki TextField ile neden çalışmıyor?

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.

Boş bir alana dokunulduğunda klavye nasıl gizlenir?

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 ile klavye görünümü nasıl canlandırılır?

@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

  • @FocusState — giriş odağı yönetimi için yerel bir SwiftUI property wrapper, iOS 15'ten itibaren kullanılabilir.
  • İki mod — tek bir alan için Bool, birden çok form alanı için Hashable enum.
  • .focused() değiştiricisi — @FocusState'i belirli bir giriş alanına bağlamak için zorunludur.
  • Programlı kontrol — değeri nil veya false olarak ayarlamak klavyeyi gizler.
  • Form doğrulama — @FocusState, doğrulamadan sonra ilk hatalı alana odak ayarlamaya izin verir.
  • Birden çok alan için Enum — birden çok Bool özelliği yerine enum ile tek bir @FocusState tercih edilir.
  • iOS 15+ — eski sürümler için, becomeFirstResponder ile UIViewRepresentable kullanın.

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.

Projeyi tartış

Ayrıca okuyun