这篇文章介绍了 SwiftUI 中的 FocusState 属性包装器,它允许我们读取和写入视图层次结构中的当前焦点位置。作者演示了如何使用 FocusState 属性包装器和聚焦视图修饰符在 SwiftUI 应用程序中管理焦点,并给出了多个输入框的焦点判断的例子。同时,作者还介绍了如何使用符合 Hashable 协议的枚举类型对聚焦状态进行建模。
本文为翻译内容,来自swiftwithmajid
翻译:张洪Heo
推荐访问原文地址:立即访问
SwiftUI 在上次 WWDC 期间变得非常强大。我们获得了许多新功能,其中之一是全新的FocusState属性包装器。FocusState属性包装器允许我们读取和写入视图层次结构中的当前焦点位置。本周我们将学习如何使用FocusState属性包装器和聚焦视图修饰符在 SwiftUI 应用程序中管理焦点。
关于FocusState
SwiftUI 提供了一个新的FocusState属性包装器,适用于所有 Apple 平台,并允许我们专注于特定视图或检查该视图是否已经获得焦点。使用起来毫不费力。让我们看看如何使用它。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 
 | 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("email"))
 .focused($isEmailFocused)
 }
 .navigationTitle("Sign in")
 .onChange(of: isEmailFocused) { newValue in
 print(newValue)
 }
 }
 }
 }
 
 | 
焦点绑定
正如你在上面的示例中看到的,我们需要使用FocusState属性包装器定义一个布尔变量。我们也有它的价值结合使用特定视图的焦点状态集中视图调节。一旦用户关注它,SwiftUI 就会将视图的布尔值设置为 true。一旦视图失去焦点,它也会将其更改为 false。
你可以根据需要定义任意数量的 FocusState变量来覆盖你的焦点管理逻辑。SwiftUI 通过将焦点视图与其绑定保持同步来处理它们。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 
 | 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("email"))
 .focused($isEmailFocused)
 SecureField("password", text: $password, prompt: Text("password"))
 .focused($isPasswordFocused)
 }
 .navigationTitle("Sign in")
 }
 }
 }
 
 | 
在上面的例子中,我们有两个变量绑定到电子邮件和密码文本字段。SwiftUI 可以一起管理它们并使它们与用户界面保持同步。请记住,你可以通过编程方式将该值更改为 false 以隐藏键盘或将该值设置为 true 以将焦点移动到特定视图。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 
 | 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("email"))
 .focused($isEmailFocused)
 SecureField("password", text: $password, prompt: Text("password"))
 .focused($isPasswordFocused)
 
 Button("login") {
 if email.isEmpty {
 isEmailFocused = true
 } else if password.isEmpty {
 isPasswordFocused = true
 } else {
 isPasswordFocused = false
 isEmailFocused = false
 
 login()
 }
 }
 }
 .navigationTitle("Sign in")
 }
 }
 
 private func login() {
 
 }
 }
 
 | 
多个输入框的焦点判断
在复杂的视图层次结构中定义许多FocusState属性会变得很麻烦。幸运的是,FocusState不仅适用于布尔值,还适用于任何Hashable类型。这意味着我们可以使用符合Hashable协议的枚举类型对聚焦状态进行建模。让我们来看看这个例子。
| 12
 3
 4
 
 | enum FocusableField: Hashable {case email
 case password
 }
 
 | 
这里我们有符合Hashable的Field枚举并定义了我们管理的所有可聚焦视图。现在,我们可以使用这个枚举将不同视图的焦点状态绑定到各种枚举案例。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 
 | 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() {
 
 }
 }
 
 | 
如你所见,我们使用了另一个版本的聚焦视图修饰符来将视图绑定到Field枚举的具体情况。每当用户关注任何绑定视图时,SwiftUI都会更新FocusState属性的值。请记住,我们应该将FocusState属性设为可选,以便与Hashable枚举结合使用,因为目前可能没有聚焦视图。


张洪Heo
分享设计与科技生活
本文是转载或翻译文章,版权归原作者所有。建议访问原文,转载本文请联系原作者。