SwiftUI中MessageKit输入栏随键盘上移至顶部问题的解决方法
问题:SwiftUI集成MessageKit时键盘弹出输入栏跳至顶部的修复方案
我基于SwiftUI开发应用,集成MessageKit实现聊天功能,但键盘弹出时,输入栏会异常跳至屏幕顶部。
当前SwiftUI表现:
预期效果(UIKit版本):
如何修复SwiftUI实现中的输入栏位置,或在SwiftUI应用中达成该预期效果?
我的相关代码片段
1. UIViewController创建代码
func makeUIViewController(context: Context) -> MessagesViewController { let messagesVC = MessageSwiftUIVC() messagesVC.messagesCollectionView.messagesDisplayDelegate = context.coordinator messagesVC.messagesCollectionView.messagesLayoutDelegate = context.coordinator messagesVC.messagesCollectionView.messagesDataSource = context.coordinator messagesVC.scrollsToLastItemOnKeyboardBeginsEditing = true // 默认false messagesVC.maintainPositionOnInputBarHeightChanged = true // 默认false messagesVC.showMessageTimestampOnSwipeLeft = true // 默认false return messagesVC }
2. InputBar代理实现
extension MessagesView.Coordinator: InputBarAccessoryViewDelegate { func inputBar(_ inputBar: InputBarAccessoryView, didPressSendButtonWith text: String) { let message = Message(sender: currentUser, messageId: "1", sentDate: Date(), kind: .text("Hello, World!")) messages.wrappedValue.append(message) inputBar.inputTextView.text = "" } }
修复方案
1. 确保自定义MessagesViewController的输入栏约束正确
在你的MessageSwiftUIVC子类中,检查并修正输入栏的底部约束,确保它绑定到视图的安全区域底部,避免约束失效:
class MessageSwiftUIVC: MessagesViewController { override func viewDidLoad() { super.viewDidLoad() // 禁用UIKit自动调整滚动视图Insets,避免和SwiftUI的适配逻辑冲突 automaticallyAdjustsScrollViewInsets = false // 重置输入栏约束(以SnapKit为例,Auto Layout可对应修改) inputBar.removeConstraints(inputBar.constraints) inputBar.snp.makeConstraints { make in make.left.right.equalTo(view.safeAreaLayoutGuide) make.bottom.equalTo(view.safeAreaLayoutGuide) } } }
2. 调整SwiftUI宿主视图的键盘适配逻辑
在SwiftUI中包裹UIViewControllerRepresentable时,忽略键盘区域的安全区适配,避免SwiftUI的自动调整干扰MessageKit的输入栏位置:
struct ContentView: View { var body: some View { MessagesView() .ignoresSafeArea(.keyboard, edges: .bottom) } }
3. 禁用MessageKit内置键盘处理,改用自定义监听
如果内置的键盘适配逻辑和SwiftUI冲突,可关闭相关设置,手动监听键盘通知调整输入栏:
class MessageSwiftUIVC: MessagesViewController { override func viewDidLoad() { super.viewDidLoad() // 关闭MessageKit内置的键盘相关自动调整 scrollsToLastItemOnKeyboardBeginsEditing = false maintainPositionOnInputBarHeightChanged = false // 注册键盘通知 NotificationCenter.default.addObserver( self, selector: #selector(keyboardFrameChanged(_:)), name: UIResponder.keyboardWillChangeFrameNotification, object: nil ) } @objc private func keyboardFrameChanged(_ notification: Notification) { guard let userInfo = notification.userInfo, let keyboardEndFrame = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect else { return } let keyboardHeight = view.convert(keyboardEndFrame, from: nil).height - view.safeAreaInsets.bottom inputBar.snp.updateConstraints { make in make.bottom.equalTo(view.safeAreaLayoutGuide).inset(keyboardHeight) } view.layoutIfNeeded() // 手动滚动到最后一条消息 messagesCollectionView.scrollToLastItem(at: .bottom, animated: true) } deinit { NotificationCenter.default.removeObserver(self) } }
4. 检查是否重写了inputBar属性
如果自定义了inputBar的getter方法,需确保初始化时正确设置了约束,避免覆盖MessageKit的默认布局:
// 错误示例:重写inputBar但未设置约束 // override var inputBar: InputBarAccessoryView { // let bar = InputBarAccessoryView() // // 未设置约束会导致位置异常 // return bar // } // 正确示例(若必须重写) override var inputBar: InputBarAccessoryView { let bar = InputBarAccessoryView() // 初始化时绑定约束到父视图 bar.translatesAutoresizingMaskIntoConstraints = false return bar }
内容的提问来源于stack exchange,提问作者aa._.ron
相关产品推荐
相关产品推荐

