如何在SwiftUI中添加键盘收起时仍常驻显示的键盘工具栏
SwiftUI 实现常驻底部 inputAccessoryView 的方案
原生 SwiftUI 提供的 .toolbar(placement: .keyboard) API 仅会在键盘弹出时渲染视图,没有公开参数支持键盘收起后常驻显示,你可以通过桥接 UIKit 的 inputAccessoryView 能力实现需求,既保留系统级的键盘跟随动画效果,又能实现工具栏常驻。
具体实现
1. 封装 UIKit 桥接层
import SwiftUI import UIKit struct AccessoryViewHost<Content: View>: UIViewControllerRepresentable { let content: Content @Binding var isFirstResponder: Bool init(isFirstResponder: Binding<Bool>, @ViewBuilder content: () -> Content) { self._isFirstResponder = isFirstResponder self.content = content() } func makeUIViewController(context: Context) -> AccessoryViewController<Content> { let vc = AccessoryViewController<Content>() vc.accessoryContent = content return vc } func updateUIViewController(_ uiViewController: AccessoryViewController<Content>, context: Context) { uiViewController.accessoryContent = content if isFirstResponder { uiViewController.becomeFirstResponder() } else { uiViewController.resignFirstResponder() } } } class AccessoryViewController<Content: View>: UIViewController { var accessoryContent: Content? { didSet { hostController.rootView = accessoryContent hostController.view.sizeToFit() } } private lazy var hostController = UIHostingController(rootView: accessoryContent) override var canBecomeFirstResponder: Bool { true } override var inputAccessoryView: UIView? { hostController.view } }
2. SwiftUI 层调用示例
struct ChatView: View { // 保持为true即可让工具栏常驻,设为false可临时隐藏工具栏 @State private var isAccessoryActive = true @State private var inputText = "" var body: some View { VStack(spacing: 0) { // 聊天消息列表 List(0..<100) { index in Text("聊天消息 \(index)") } .listStyle(.plain) // 输入框区域 HStack { TextField("输入内容", text: $inputText) .textFieldStyle(.roundedBorder) Button("发送") { // 发送逻辑 } } .padding() } .background { // 挂载常驻工具栏 AccessoryViewHost(isFirstResponder: $isAccessoryActive) { HStack(spacing: 24) { Button("表情") { /* 表情逻辑 */ } Button("图片") { /* 选图逻辑 */ } Button("语音") { /* 语音逻辑 */ } Spacer() Button("更多") { /* 拓展功能逻辑 */ } } .padding(.horizontal, 16) .padding(.vertical, 12) .background(Color(.systemGray5)) } } .onTapGesture { // 点击空白收起键盘,不会隐藏工具栏 UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil) } } }
注意事项
- 该方案完全复用 UIKit 原生
inputAccessoryView能力,工具栏动画和系统键盘完全同步,不会出现自定义视图常见的动画错位、掉帧问题 - 该方案最低支持 iOS 14,如需兼容更早版本,可将桥接层中的 UIHostingController 替换为纯 UIKit 实现的工具栏视图
- 输入框不需要放在工具栏内,可以正常放在页面的层级中,不会影响动画效果
内容的提问来源于stack exchange,提问作者alionthego
相关产品推荐
相关产品推荐

