如何在兼容iOS14的SwiftUI应用中仅为iOS15启用FocusState
兼容iOS14的SwiftUI实现点击按钮激活文本框键盘
问题分析
你无法直接用#available修饰@FocusState属性的原因是:@FocusState作为属性包装器,Swift不允许单独为其添加版本可用性声明。需要针对iOS15+和iOS14分别实现焦点控制逻辑。
解决方案
我们可以通过条件编译区分系统版本,iOS15+使用原生FocusState,iOS14则借助UIKit的UITextField实现焦点激活:
完整代码实现
import SwiftUI import UIKit struct ContentView: View { @State private var username = "" // 仅在iOS15+编译该属性 #if compiler(>=5.5) && os(iOS 15.0) @FocusState private var isUsernameFocused: Bool #endif var body: some View { VStack(spacing: 30) { // 原生SwiftUI TextField TextField("请输入用户名", text: $username) .textFieldStyle(.roundedBorder) .padding(.horizontal) // iOS15+绑定FocusState #if compiler(>=5.5) && os(iOS 15.0) .focused($isUsernameFocused) #endif Button("激活键盘") { #if compiler(>=5.5) && os(iOS 15.0) // iOS15+直接设置FocusState激活焦点 isUsernameFocused = true #else // iOS14通过UIKit找到对应文本框并激活 guard let keyWindow = UIApplication.shared.windows.first(where: { $0.isKeyWindow }) else { return } if let targetTextField = keyWindow.viewWithTag(1001) as? UITextField { targetTextField.becomeFirstResponder() } #endif } .buttonStyle(.borderedProminent) } // iOS14下添加隐藏的UIKit TextField同步文本并处理焦点 #if os(iOS 14.0) .overlay( UIKitUsernameTextField(text: $username) .opacity(0) // 隐藏UIKit文本框,仅用于同步和焦点控制 ) #endif } } // iOS14专属的UIKit TextField封装 #if os(iOS 14.0) struct UIKitUsernameTextField: UIViewRepresentable { @Binding var text: String func makeUIView(context: Context) -> UITextField { let textField = UITextField() textField.tag = 1001 // 设置唯一标识用于查找 textField.addTarget(context.coordinator, action: #selector(Coordinator.textDidChange), for: .editingChanged) return textField } func updateUIView(_ uiView: UITextField, context: Context) { // 同步SwiftUI的文本到UIKit文本框 if uiView.text != text { uiView.text = text } } func makeCoordinator() -> Coordinator { Coordinator(parent: self) } class Coordinator: NSObject { private let parent: UIKitUsernameTextField init(parent: UIKitUsernameTextField) { self.parent = parent } // 同步UIKit文本框内容到SwiftUI的State @objc func textDidChange(_ textField: UITextField) { parent.text = textField.text ?? "" } } } #endif
代码说明
iOS15+逻辑:
- 用条件编译声明
@FocusState属性,通过focused($isUsernameFocused)绑定到TextField - 按钮点击时直接设置
isUsernameFocused = true,即可激活键盘
- 用条件编译声明
iOS14逻辑:
- 封装
UIKitUsernameTextField作为UIViewRepresentable,设置唯一tag用于查找 - 将该文本框隐藏在原生SwiftUI TextField下方,同步文本内容
- 按钮点击时通过UIKit API找到对应文本框,调用
becomeFirstResponder()激活键盘
- 封装
内容的提问来源于stack exchange,提问作者dhaval123
相关产品推荐
相关产品推荐

