SwiftUI如何实现类似UIKit的全局InputAccessoryView让输入区跟随键盘移动
SwiftUI 全局 inputAccessoryView 实现方案
SwiftUI 原生未直接提供全局 inputAccessoryView 的公开API,你可以通过桥接 UIKit 根视图控制器的方式实现和之前 UIKit 开发完全一致的效果,满足输入视图全局可见、跟随键盘拖拽同步移动的需求,不需要绑定到特定TextField。
实现步骤
- 第一步:创建重写了
inputAccessoryView的自定义UIViewController子类
class InputAccessoryHostingController<Content: View>: UIViewController { private let accessoryView = UIView() private let rootView: Content init(rootView: Content) { self.rootView = rootView super.init(nibName: nil, bundle: nil) setupAccessoryView() } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } override var canBecomeFirstResponder: Bool { true } override var inputAccessoryView: UIView? { accessoryView } private func setupAccessoryView() { // 把SwiftUI自定义输入视图嵌入到accessoryView中 let hostingController = UIHostingController(rootView: rootView) addChild(hostingController) accessoryView.addSubview(hostingController.view) hostingController.view.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ hostingController.view.topAnchor.constraint(equalTo: accessoryView.topAnchor), hostingController.view.leadingAnchor.constraint(equalTo: accessoryView.leadingAnchor), hostingController.view.trailingAnchor.constraint(equalTo: accessoryView.trailingAnchor), hostingController.view.bottomAnchor.constraint(equalTo: accessoryView.bottomAnchor) ]) hostingController.didMove(toParent: self) // 自动计算accessoryView的高度 accessoryView.autoresizingMask = .flexibleHeight } }
- 第二步:用
UIViewControllerRepresentable桥接为SwiftUI视图
struct InputAccessoryHost<Content: View>: UIViewControllerRepresentable { let content: Content init(@ViewBuilder content: () -> Content) { self.content = content() } func makeUIViewController(context: Context) -> InputAccessoryHostingController<Content> { let vc = InputAccessoryHostingController(rootView: content) // 页面加载后立刻成为第一响应者,保证inputAccessory全局生效 DispatchQueue.main.async { vc.becomeFirstResponder() } return vc } func updateUIViewController(_ uiViewController: InputAccessoryHostingController<Content>, context: Context) {} }
- 第三步:在你的根SwiftUI视图中引入该组件,放在
background层级即可,不会影响原有视图布局
struct ChatRootView: View { var body: some View { NavigationStack { // 你的聊天列表、输入框等原有内容 List { // 聊天消息cell } } .background { // 全局inputAccessory,传入你自定义的输入视图 InputAccessoryHost { CustomChatInputView() // 你自己实现的SwiftUI输入视图 } .ignoresSafeArea() } } }
效果说明
该实现完全复用UIKit系统的inputAccessory逻辑,不需要手动监听键盘通知做位移动画,输入视图会跟随键盘的交互式拖拽动作实时同步移动,且始终悬浮在键盘顶部,全局生效不绑定任何特定TextField。如果需要在输入框激活时做状态同步,你可以直接在CustomChatInputView中使用@FocusState管理输入框的焦点状态即可。
内容的提问来源于stack exchange,提问作者Fabio
相关产品推荐
相关产品推荐

