@FocusState — шта је то, управљање фокусом и тастатуром у SwiftUI

Аутор: IT Sectr Објављено: 2026-06-26 Време читања: 9 мин

@FocusState — је property wrapper у SwiftUI, представљен у iOS 15, који омогућава програмски управљати фокусом уноса на текстуалним пољима и другим елементима. Пре његовог појављивања, програмери су морали да користе UIViewRepresentable за приступ UIKit методама becomeFirstResponder и resignFirstResponder. @FocusState решава овај проблем нативним начином: повезујете својство са пољем путем модификатора .focused(), након чега постављање или поништавање фокуса се дешава једноставним додељивањем вредности. Према Apple Developer Documentation — FocusState (2025), @FocusState подржава два режима: Bool за једноставно управљање (фокус постоји или не) и enum за више поља, где сваки case одговара одређеном пољу уноса.

Главно

  • @FocusState — property wrapper за програмско управљање фокусом у SwiftUI, доступан од iOS 15.
  • Bool режим — за једно поље користи @FocusState var isFocused: Bool са .focused($isFocused).
  • Enum режим — за више поља користи enum са протоколом FocusStateValue и .focused($field, equals: .fieldName).
  • Сакривање тастатуре — постави фокус на nil или false да би сакрио тастатуру.
  • Аутоматски фокус — постави почетну вредност у .onAppear да би приказао тастатуру при отварању екрана.

Шта је @FocusState у SwiftUI

@FocusState — је property wrapper који повезује стање фокуса са одређеним пољем за унос или другим focusable елементом у SwiftUI. За разлику од UIKit-а, где се управљање фокусом врши кроз методе becomeFirstResponder и resignFirstResponder, SwiftUI користи декларативни приступ: декларишете стање (@FocusState) и повезујете га са елементом путем модификатора .focused(). Промена стања аутоматски мења фокус.

Пре појаве @FocusState у iOS 15, програмери су морали да креирају UIViewRepresentable омотаче око UITextField или да користе библиотеке трећих страна. @FocusState је интегрисан директно у SwiftUI и ради са TextField, TextEditor, SecureField и SearchField. То чини код чишћим, смањује број UIKit мостова и побољшава тестирање.

Према WWDC Session 10136 — What's new in SwiftUI (2024), @FocusState користи SwiftUI систем preference кључева за преношење информација о фокусу између елемената. Када поље прими фокус, SwiftUI аутоматски ажурира повезано @FocusState својство, што омогућава реаговање на промене фокуса у коду.

Управљање фокусом са Bool

Најједноставнији начин коришћења @FocusState — Bool тип. Када је поље у фокусу, својство је true. Када фокус одлази — false. Можете принудно поставити фокус додељивањем true или га поништити додељивањем false.

swift
struct LoginForm: View {
    @State var email = ""
    @FocusState var isEmailFocused: Bool
    
    var body: some View {
        VStack {
            TextField("Email", text: $email)
                .focused($isEmailFocused)
            
            Button("Prikaži tastaturu") {
                isEmailFocused = true
            }
            Button("Sakrij tastaturu") {
                isEmailFocused = false
            }
        }
    }
}

У овом примеру, isEmailFocused аутоматски постаје true када корисник додирне текстуално поље, и false када је тастатура сакривена. Дугмићи омогућавају програмско управљање фокусом — корисно за прилагођене тастатуре, дугмиће „Даље” и ситуације када је потребно принудно сакрити тастатуру након слања формулара.

Управљање фокусом са Enum за више поља

За формуларе са више поља, @FocusState подржава enum који одговара протоколу FocusStateValue (или Hashable). Сваки case enum-а одговара одређеном пољу. Ово омогућава пребацивање фокуса између поља — на пример, прилиском на „Даље” на тастатури прелазите на следеће поље.

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 — позива се када корисник притисне „Return” на тастатури. Унутар .onSubmit пребацујемо focusedField на следеће поље, што аутоматски помера фокус. Последње поље позива submitForm() за слање формулара.

Сакривање и приказивање тастатуре

@FocusState пружа једноставан начин да сакријете тастатуру — довољно је да поставите својство на nil (за enum) или false (за Bool). Међутим, понекад је потребно сакрити тастатуру без везе за одређено поље — на пример, при додиру на празан простор. У овом случају постоји неколико приступа.

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("Gotovo") {
                        isFocused = false
                    }
                }
            }
    }
}

Модификатор .toolbar са placement .keyboard додаје дугме изнад тастатуре. Ово је стандардни UX образац у iOS-у за сакривање тастатуре. Алтернативни приступ — коришћење .onTapGesture на коренском VStack-у за поништавање фокуса при додиру на позадину.

Фокус и валидација формулара

@FocusState се одлично комбинује са валидацијом формулара. Типичан образац: након притиска на дугме „Пошаљи”, проверите сва поља и поставите фокус на прво поље са грешком. Ово побољшава корисничко искуство — корисник одмах види које поље треба поправити.

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("Pošalji") { validateAndSubmit() }
        }
    }
    
    func validateAndSubmit() {
        if name.isEmpty {
            focusedField = .name
            return
        }
        if phone.isEmpty {
            focusedField = .phone
            return
        }
        // pošalji formular
    }
}

У овом примеру, када је поље name празно, фокус се помера на њега и корисник одмах види где је грешка. Ако је name попуњено, проверава се phone. Ово је природно понашање за формуларе — корисник пољунава поља одозго надоле, а валидација прати исти редослед.

Типичне грешке са @FocusState

Најчешћа грешка — покушај коришћења @FocusState са типом који није Hashable. @FocusState захтева да тип својства буде Hashable (Bool и опционални enum већ јесу усаглашени). Ако покушавате да користите прилагођену структуру, уверите се да имплементира Hashable.

  • Заборавили сте .focused() модификатор — @FocusState сам по себи не управља фокусом. Морате га повезати са пољем путем .focused($property) или .focused($property, equals: .case).
  • Више @FocusState у једном View-у — за више поља користите један @FocusState са enum, а не више @FocusState својстава. Више Bool својстава неће бити синхронизовано међусобно.
  • Промена @FocusState ван main thread-а — @FocusState се мора мењати само на главном ниту, као и сва UI својства у SwiftUI-у. Асинхроне операције треба да се пребаце на MainActor пре промене.
  • Ресетовање фокуса при поновном изградњи — ако се View поново изгради, @FocusState се може ресетовати. Користите .id() модификатор за стабилну идентификацију View-а.
swift
// ❌ Greška: dva @FocusState Bool umesto enum
@FocusState var isNameFocused: Bool
@FocusState var isEmailFocused: Bool

// ✅ Ispravno: jedan enum @FocusState
enum Field: Hashable { case name; case email }
@FocusState var focusedField: Field?

Често постављана питања

Од којих верзија iOS је @FocusState доступан?

@FocusState је доступан од iOS 15, iPadOS 15, macOS 12, tvOS 15 и watchOS 8. За пројекте који подржавају iOS 14 и ниже, користите UIViewRepresentable са UITextField и becomeFirstResponder, или библиотеке трећих страна са прилагођеном имплементацијом управљања фокусом.

Може ли се @FocusState користити са прилагођеним UIViewRepresentable?

Да, за ово је потребно да имплементирате подршку за FocusState у прилагођеном UIViewRepresentable кроз протокол UIViewRepresentable. Прилагођени view мора да има becomeFirstResponder и resignFirstResponder. SwiftUI ће аутоматски повезати @FocusState са овим методама ако наведете .focused() модификатор.

Зашто @FocusState не ради са TextField у List-у?

У List или Form-у, ћелије се могу поново користити, што квари @FocusState везу са пољем. Решење: додајте .id() модификатор са јединственим идентификатором за сваки TextField. На пример: .id(fieldName). Ово принудно тера SwiftUI да креира посебну инстанцу View-а за свако поље.

Како сакрити тастатуру при додиру на празан простор?

Додајте .onTapGesture на коренски контејнер (VStack, ZStack) и ресетујте фокус: focusedField = nil. Међутим, .onTapGesture може да блокира додире на дугмиће унутар — користите контејнер са .contentShape(Rectangle()) и .onTapGesture на њему, или прилагођени UIKitBackgroundView.

Како анимирати појаву тастатуре са @FocusState?

@FocusState не пружа директни API за анимацију тастатуре — ово је системско понашање iOS-а. Ипак можете реаговати на промене фокуса помоћу .onChange(of: focusedField) или .onReceive(NotificationCenter.default.publisher(for: UIResponder.keyboardWillShowNotification)) за прилагођену анимацију садржаја.

Резиме

  • @FocusState — нативни SwiftUI property wrapper за управљање фокусом уноса, доступан од iOS 15.
  • Два режима — Bool за једно поље, Hashable enum за више поља формулара.
  • .focused() модификатор — обавезан за повезивање @FocusState са одређеним пољем за унос.
  • Програмско управљање — постављање вредности nil или false сакрива тастатуру.
  • Валидација формулара — @FocusState омогућава постављање фокуса на прво поље са грешком након провере.
  • Enum за више поља — један @FocusState са enum је пожељан од више Bool својстава.
  • iOS 15+ — за старије верзије користите UIViewRepresentable са becomeFirstResponder.

Развићемо мобилну апликацију под кључ

IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.

Разговарајте о пројекту

Прочитајте такође