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

如何基于JSQMessageViewController创建新消息与自定义会话UI?

在JSQMessagesViewController中添加“To”收件人栏的实现指引

嘿,我刚好之前做过类似的需求,给你分享几个靠谱的实现方案,都是基于JSQ自带UI扩展的,不用完全重构现有界面:


方案一:自定义导航栏集成收件人栏

JSQ的导航栏默认只显示标题,我们可以把它替换成包含“To”标签和收件人展示/输入的自定义View,这样既贴合原有UI风格,又不破坏整体布局结构:

  1. 创建自定义收件人栏视图
    先写一个RecipientBarView,包含“To:”标签和收件人展示/输入控件,示例代码如下:

    class RecipientBarView: UIView {
        let toLabel = UILabel()
        let recipientContent = UILabel() // 如果需要编辑可以换成UITextField
        
        override init(frame: CGRect) {
            super.init(frame: frame)
            setupUI()
        }
        
        required init?(coder: NSCoder) {
            super.init(coder: coder)
            setupUI()
        }
        
        private func setupUI() {
            backgroundColor = .systemBackground
            toLabel.text = "To:"
            toLabel.font = UIFont.systemFont(ofSize: 16, weight: .medium)
            recipientContent.font = UIFont.systemFont(ofSize: 16)
            recipientContent.textColor = .systemBlue
            
            // 用StackView做自适应布局
            let stackView = UIStackView(arrangedSubviews: [toLabel, recipientContent])
            stackView.spacing = 8
            stackView.translatesAutoresizingMaskIntoConstraints = false
            addSubview(stackView)
            
            NSLayoutConstraint.activate([
                stackView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 16),
                stackView.centerYAnchor.constraint(equalTo: centerYAnchor),
                stackView.trailingAnchor.constraint(lessThanOrEqualTo: trailingAnchor, constant: -16)
            ])
        }
        
        // 提供更新收件人的方法
        func updateRecipientName(_ name: String) {
            recipientContent.text = name
        }
    }
    
  2. 替换JSQ的导航栏标题视图
    在你的JSQMessagesViewController子类的viewDidLoad方法里,把导航栏的titleView换成我们的自定义视图:

    override func viewDidLoad() {
        super.viewDidLoad()
        
        // 初始化并配置收件人栏
        let recipientBar = RecipientBarView(frame: CGRect(x: 0, y: 0, width: view.frame.width - 40, height: 44))
        recipientBar.updateRecipientName("Sarah") // 替换成你的收件人数据
        navigationItem.titleView = recipientBar
        
        // 其他JSQ基础配置
        collectionView?.collectionViewLayout.incomingMessageViewAlignment = .left
        collectionView?.collectionViewLayout.outgoingMessageViewAlignment = .right
        inputToolbar.contentView.textView.placeholder = "输入消息..."
    }
    

    如果需要支持编辑收件人,把recipientContent换成UITextField,再处理键盘弹出/收起的逻辑即可。


方案二:在消息列表顶部添加固定头部

如果不想修改导航栏,可以给JSQ的collectionView添加一个固定在顶部的头部视图作为“To”栏,它会跟着消息列表滚动但始终保持在可视区域顶部:

  1. 注册头部视图并配置布局
    在viewDidLoad里完成头部视图的注册和布局设置:

    override func viewDidLoad() {
        super.viewDidLoad()
        
        // 注册自定义头部视图
        collectionView?.register(RecipientHeaderView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "RecipientHeader")
        
        // 配置头部固定在顶部及高度
        if let layout = collectionView?.collectionViewLayout as? JSQMessagesCollectionViewFlowLayout {
            layout.sectionHeadersPinToVisibleBounds = true
            layout.headerReferenceSize = CGSize(width: view.frame.width, height: 44)
        }
    }
    

    这里的RecipientHeaderView可以复用方案一的UI布局,只需把父类改成UICollectionReusableView。

  2. 实现头部视图的数据源方法
    重写JSQ的collectionView(_:viewForSupplementaryElementOfKind:at:)方法,返回自定义头部:

    override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
        let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "RecipientHeader", for: indexPath) as! RecipientHeaderView
        header.updateRecipientName("John Doe") // 更新收件人信息
        return header
    }
    

关键注意事项

  • 避免输入工具栏重叠:如果用方案二,要调整collectionView的内边距,防止消息列表被底部输入栏挡住:
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        if let layout = collectionView?.collectionViewLayout as? JSQMessagesCollectionViewFlowLayout {
            collectionView?.contentInset = UIEdgeInsets(top: 44, left: 0, bottom: layout.inputToolbarHeight, right: 0)
        }
    }
    
  • 适配深色模式:给自定义视图的文字、背景色设置动态颜色(比如UIColor.label、UIColor.systemBackground),和JSQ原生UI保持风格统一。
  • 数据同步:如果是从其他页面跳转过来,记得在初始化JSQMessagesViewController子类时传入收件人数据,再调用更新方法刷新视图。

这样改造后,你的界面就会在JSQ原有UI基础上完美添加“To”栏,既符合原生风格,又满足功能需求啦!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 07:02:15