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

SwiftUI中MessageKit输入栏随键盘上移至顶部问题的解决方法

问题:SwiftUI集成MessageKit时键盘弹出输入栏跳至顶部的修复方案

我基于SwiftUI开发应用,集成MessageKit实现聊天功能,但键盘弹出时,输入栏会异常跳至屏幕顶部。

当前SwiftUI表现:
Current SwiftUI Behavior

预期效果(UIKit版本):
Expected Behavior(with 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 19:53:08