You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在兼容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

代码说明

  1. iOS15+逻辑:

    • 用条件编译声明@FocusState属性,通过focused($isUsernameFocused)绑定到TextField
    • 按钮点击时直接设置isUsernameFocused = true,即可激活键盘
  2. iOS14逻辑:

    • 封装UIKitUsernameTextField作为UIViewRepresentable,设置唯一tag用于查找
    • 将该文本框隐藏在原生SwiftUI TextField下方,同步文本内容
    • 按钮点击时通过UIKit API找到对应文本框,调用becomeFirstResponder()激活键盘

内容的提问来源于stack exchange,提问作者dhaval123

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 00:47:25