SwiftUI Release 引入的輔助焦點管理

Swift社区發表於2024-10-29

前言

SwiftUI Release 引入了強大的新功能,其中之一是輔助焦點管理。

這個新功能使得在SwiftUI中處理輔助技術(如 VoiceOver 和 Switch Control)的焦點狀態變得更加輕鬆。本文將介紹如何使用 @FocusState 屬性包裝器來在SwiftUI中管理和移動輔助焦點。

使用 @FocusState 屬性包裝器

在 SwiftUI Release 中,我們獲得了一整套特殊工具來更有效地處理輔助焦點。其中包括 @FocusState 屬性包裝器和 focused 檢視修飾符。透過使用這些工具,我們能夠以與無輔助技術相同的方式處理輔助焦點。

核心程式碼如下:

import SwiftUI

struct SignInView: View {
    @FocusState
    private var isEmailFocused: Bool

    @State private var email = ""

    var body: some View {
        NavigationView {
            Form {
                TextField("Email", text: $email, prompt: Text("Enter your email"))
                    .focused($isEmailFocused)
            }
            .navigationTitle("Sign In")
            .onChange(of: isEmailFocused) { newValue in
                print(newValue)
            }
        }
    }
}

如上例所示,我們使用 @FocusState 屬性包裝器定義一個變數,表示 email 欄位是否聚焦。SwiftUI 預設使用 false 值初始化該變數,因為使用者可以聚焦螢幕的任何其他區域。我們還使用 focused 檢視修飾符將特定檢視的焦點狀態繫結到儲存其值的變數。

請記住,您可以宣告盡需要的變數,以使用 @FocusState 屬性包裝器涵蓋輔助焦點邏輯。

高階技巧:專用輔助技術

核心程式碼如下:

import SwiftUI

struct SignInView: View {
    @FocusState
    private var isEmailFocused: Bool
    
    @FocusState
    private var isPasswordFocused: Bool

    @State private var email = ""
    @State private var password = ""

    var body: some View {
        NavigationView {
            Form {
                TextField("Email", text: $email, prompt: Text("Enter your email"))
                    .focused($isEmailFocused)
                SecureField("Password", text: $password, prompt: Text("Enter your password"))
                    .focused($isPasswordFocused)
            }
            .navigationTitle("Sign In")
        }
    }
}

@FocusState 屬性包裝器的好處之一是您可以將其行為限制為專用輔助技術。例如,您可以僅為VoiceOver或Switch Control啟用 @FocusState 屬性包裝器。預設情況下,SwiftUI 會將裝置上可用的所有輔助技術的值進行聚合。

可聚焦欄位的高階用法

核心程式碼如下:

import SwiftUI

struct SignInView: View {
    @FocusState(for: .switchControl)
    private var isEmailFocused: Bool

    @State private var email = ""

    var body: some View {
        NavigationView {
            Form {
                TextField("Email", text: $email, prompt: Text("Enter your email"))
                    .focused($isEmailFocused)
            }
            .navigationTitle("Sign In")
            .onChange(of: isEmailFocused) { newValue in
                print(newValue)
            }
        }
    }
}

如上例所示,我們使用 @FocusState 屬性包裝器為 Switch Control 定義了可選變數 isEmailFocused,以便在使用者在檢視之間移動焦點時進行切換。

通常,螢幕上有多個元素,您可能希望在它們之間移動焦點。為了支援這種情況,SwiftUI 提供了一種透過列舉定義可聚焦欄位並在它們之間切換的方法。這種方法是使用 @FocusState 屬性包裝器,併為其提供一個用於標識焦點型別的引數(在此例中是 .switchControl)。

最佳化體驗

全部程式碼如下:

import SwiftUI

enum FocusableField: Hashable {
    case email
    case password
}

struct ContentView: View {
    @State private var email = ""
    @State private var password = ""
    
    @FocusState
    private var focus: FocusableField?

    var body: some View {
        NavigationView {
            Form {
                TextField("email", text: $email, prompt: Text("email"))
                    .focused($focus, equals: .email)
                SecureField("password", text: $password, prompt: Text("password"))
                    .focused($focus, equals: .password)
                Button("login", action: login)
            }
            .toolbar {
                ToolbarItem(placement: .keyboard) {
                    Button("next") {
                        if email.isEmpty {
                            focus = .email
                        } else if password.isEmpty {
                            focus = .password
                        } else {
                            focus = nil
                        }
                    }
                }
            }
            .navigationTitle("Sign in")
            .onAppear {
                DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
                    focus = .email
                }
            }
        }
    }

    private func login() {
        // your logic here
    }
}

執行截圖

如上例所示,我們使用了 @FocusState 屬性包裝器與我們的新 FocusableField 列舉一起使用。該列舉定義了螢幕上所有可聚焦檢視,應確保 FocusableField 列舉是可雜湊的。

使用 @FocusState 屬性包裝器定義了可選變數 focus,以便在使用者將焦點從您定義的檢視移動時將其值設定為 nil

我們還使用了 focused 修飾符的一個版本,將一個檢視繫結到可雜湊列舉的特定情況。請記住,您可以透過更改 @FocusState 包裝的變數的值來以程式設計方式移動 VoiceOver 或 Switch Control 的焦點。

總結

在這篇文章中,我們深入探討了 SwiftUI Release 引入的輔助焦點管理功能,使得處理輔助技術(如 VoiceOver 和 Switch Control)的焦點狀態變得更加輕鬆。透過 @FocusState 屬性包裝器,我們學習瞭如何靈活地管理焦點狀態,以提高使用者體驗。透過詳細的示例程式碼,我們演示瞭如何在 SwiftUI 中使用 @FocusState,以及如何透過 focused 檢視修飾符將焦點狀態繫結到特定的檢視。此外,我們介紹了一種高階用法,透過列舉定義可聚焦欄位並在它們之間切換,以更好地支援螢幕上多個元素的焦點移動。最後,我們提供了一些最佳化 SwiftUI 應用的建議,以更好地整合焦點管理,並透過最佳實踐和總結使讀者更深入地瞭解了在 SwiftUI Release 中使用 @FocusState 管理焦點的方法。

相關文章