自定义会话列表 UI

更新时间: 2024/03/15 18:26:21

IM UIKit 的会话列表模块(NEConversationUIKit)提供会话列表界面 UI 的自定义配置项,助您快速实现该界面的 UI 个性化定制。

会话列表模块(NEConversationUIKit)提供以下两种方式对会话列表的 UI 进行个性化定制。

  • 通过接口配置的方式自定义 UI。
  • 通过源码修改的方式自定义 UI。

如果接口中的配置项满足您的界面个性化需求,请优先使用接口配置方式。

自定义功能描述

UI 元素自定义

会话列表界面可自定义的 UI 元素包括但不限于下图中的标注项。

NEKitConversationConfig 是整个会话列表的配置文件,其中 UI 实例化对象类型为 ConversationUIConfig

您可以通过 ConversationUIConfig 类中的个性化配置项,对会话列表的 UI 样式进行修改,个性化配置项具体如下:

属性 类型 说明
showTitleBar Bool 是否展示界面顶部的标题栏,具体自定义示例见下文的隐藏标题栏
showTitleBarLeftIcon Bool 是否展示标题栏左侧图标
showTitleBarRightIcon Bool 是否展示标题栏最右侧图标
showTitleBarRight2Icon Bool 是否展示标题栏次最右侧图标
titleBarLeftRes UIImage 标题栏左侧图标
titleBarRightRes UIImage 标题栏最右侧图标
titleBarRight2Res UIImage 标题栏次最右侧图标
titleBarTitle String 标题栏的文案
titleBarTitleColor UIColor 标题栏的颜色值
titleBarRightClick () -> Void 标题栏最右侧按钮点击事件
titleBarRight2Click () -> Void 标题栏次最右侧按钮点击事件
titleBarLeftClick () -> Void 标题栏左侧按钮点击事件
conversationProperties ConversationProperties 会话列表页面的 UI 个性化定制,具体配置见下文
stickTopBottonTitle String 会话列表 cell 左划置顶按钮文案内容
stickTopBottonCancelTitle String 会话列表 cell 左划取消置顶按钮文案内容
stickTopBottonColor UIColor 会话列表 cell 左划置顶按钮文案颜色
stickTopBottonClick (ConversationListModel?, IndexPath) -> Void 会话列表 cell 左划置顶按钮点击事件
deleteBottonTitle String 会话列表 cell 左划删除按钮文案内容
deleteBottonColor UIColor 会话列表 cell 左划删除按钮文案颜色
deleteBottonClick (ConversationListModel?, IndexPath) -> Void 会话列表 cell 左划删除按钮点击事件
itemClick (ConversationListModel?, IndexPath) -> Void 会话列表点击事件,包括单击和长按事件
customController (NEBaseConversationController) -> Void 自定义界面UI接口,回调中会传入会话列表界面的UI布局,您可以进行UI元素调整。

ConversationProperties类的个性化配置项具体如下:

属性 类型 说明
itemTitleColor UIColor 会话标题的字体颜色,具体示例见下文的修改会话名称字体颜色和大小
itemTitleSize CGFloat 会话标题的字体大小,具体示例见下文的修改会话名称字体颜色和大小
itemBackground UIColor 未被置顶的会话项的背景色
itemStickTopBackground UIColor 置顶的会话项的背景色
itemContentColor UIColor 会话消息缩略内容的字体颜色
itemContentSize CGFloat 会话消息缩略内容的字体大小
itemDateColor UIColor 会话时间的字体颜色
itemDateSize CGFloat 会话时间的字体大小
avatarType NEConversationAvatarType 头像类型,NEConversationAvatarType.rectangle = 1 为矩形,NEConversationAvatarType.cycle 为圆形
avatarCornerRadius CGFloat 头像圆角大小,仅在 avatarType = NEConversationAvatarType.rectangle 时有效

界面布局自定义

除了界面的 UI 元素,您也可对界面的布局进行自定义,NEConversationUIKit 模块中的 ConversationListCell 支持对会话列表界面布局进行调整, 包括界面元素调整和界面背景修改等。会话列表界面的默认视图布局如下图所示。

该界面各视图的说明如下:

属性
类型 说明
titleBarView UIView 会话列表界面标题视图,可通过navigationView来获取视图进行样式修改
navigationView TabNavigationView 会话列表界面的标题视图,可在子类直接获取视图进行样式修改,具体自定义示例请参见下文的自定义标题栏
bodyTopView UIView 会话列表上方的小块视图,可在子类直接获取视图进行样式修改。可用于在会话列表和顶部的界面标题中间增加新的 UI 元素
bodyView UIView 会话列表界面的内容视图,可在子类直接获取视图进行样式修改。布局中包含brokenNetworkView错误提示视图和contentView列表视图。
brokenNetworkView NEBrokenNetworkView 会话列表界面错误提示视图,可在子类直接获取视图进行样式修改
contentView UIView 会话列表界面的列表视图,可在子类直接获取视图进行样式修改。布局中包含tableView列表和emptyView空数据提示视图。
tableView UITableView 会话列表界面的列表,可在子类直接获取视图进行样式修改
emptyView NEEmptyDataView 会话列表界面空数据提示视图,可在子类直接获取视图进行样式修改
bodyBottomView UIView 会话列表底部的小块视图,可在子类直接获取视图进行样式修改,用于在会话列表底部增加新的 UI 元素

通过配置项自定义 UI 示例

会话列表的个性化 UI 样式需要在会话列表界面加载之前配置,您可以在 didFinishLaunchingWithOptions 方法中设置个性化定制属性。

隐藏标题栏

  • 示例代码

    Swift
    NEKitConversationConfig.shared.ui.showTitleBar = false
    
    Objective-C
    NEKitConversationConfig.shared.ui.showTitleBar = NO;
    

    除此之外,还可以隐藏标题栏中的新增图标和搜索图标。详见上文的个性化配置项列表。

  • 效果对比

    默认 自定义后
    未隐藏标题栏.png 隐藏标题栏小.png

修改会话名称字体颜色和大小

  • 示例代码

    Swift
    // 会话名称字体大小
    NEKitConversationConfig.shared.ui.conversationProperties.itemTitleSize = 24
    // 会话名称字体颜色
    NEKitConversationConfig.shared.ui.conversationProperties.itemTitleColor = UIColor.red
    
    Objective-C
    // 会话名称字体大小
    NEKitConversationConfig.shared.ui.conversationProperties.itemTitleSize = 24;
    // 会话名称字体颜色
    NEKitConversationConfig.shared.ui.conversationProperties.itemTitleColor = [UIColor redColor];
    

    除此之外,还可以修改会话中的副标题和时间的字体颜色、字体大小,详见上文的个性化配置项列表。

  • 效果对比

    默认 自定义后
    未隐藏标题栏.png 修改字体颜色和大小.png

通过源码自定义 UI 示例

NEBaseConversationController 为会话列表的实现类,内部包含会话相关的回调,具体如下:

// MARK: ================= ConversationViewModelDelegate===================

extension NEBaseConversationController: ConversationViewModelDelegate {
  //会话新增代理
  open func didAddRecentSession() {
    NELog.infoLog("ConversationController", desc: "didAddRecentSession")
    reloadTableView()
  }

  //会话更新代理
  open func didUpdateRecentSession(index: Int) {
    let indexPath = IndexPath(row: index, section: 0)
    tableView.reloadRows(at: [indexPath], with: .none)
  }

  open func reloadData() {
    delegate?.onDataLoaded()
  }

  open func didRefreshTable() {
    tableView.reloadData()
  }

  //tableView刷新代理
  open func reloadTableView() {
    emptyView.isHidden = (viewModel.conversationListArray?.count ?? 0) > 0
    viewModel.sortRecentSession()
    didRefreshTable()
  }
}

其他

自定义配置 说明
修改会话列表右侧按钮点击事件 通过 TabNavigationViewDelegate 协议中的 searchBtnClickaddBtnClick 方法进行修改
构造更多弹窗中的选项内容 通过NEBasePopListView视图类构造,当前默认设置为添加好友、创建讨论组、创建高级群
实现长按置顶会话和删除会话弹窗 请参见 NEBaseConversationControllerUITableview 中的代理方法

自定义单元格(TableviewCell)

用户可自定义会话列表单元格,实现数据的自定义展示。

实现步骤与示例代码(Swift):

  1. 继承 ConversationListCell 类,实现自定义单元格,对数据进行展示。
swiftopen class CustomConversationListCell: ConversationListCell {
  // 新增 UI 元素,用于展示在线状态
  private lazy var onlineView: UIImageView = {
    let notify = UIImageView()
    notify.translatesAutoresizingMaskIntoConstraints = false
    notify.image = UIImage(named: "about_yunxin")
    return notify
  }()

  override public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
    super.init(style: style, reuseIdentifier: reuseIdentifier)

    // 头像右下角
    contentView.addSubview(onlineView)
    NSLayoutConstraint.activate([
      onlineView.rightAnchor.constraint(equalTo: headImge.rightAnchor),
      onlineView.bottomAnchor.constraint(equalTo: headImge.bottomAnchor),
      onlineView.widthAnchor.constraint(equalToConstant: 12),
      onlineView.heightAnchor.constraint(equalToConstant: 12),
    ])
  }

  public required init?(coder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }

  // 此方法用于数据和 UI 的绑定,可在此处在数据展示前对数据进行处理
  override open func configData(sessionModel: ConversationListModel?) {
    super.configData(sessionModel: sessionModel)
//    subTitle.text = "[自定义类型文案]"
  }
}
  1. 继承 ConversationController 类,实现自定义表格(以通用皮肤为例)。
swiftopen class CustomConversationController: ConversationController, NEBaseConversationControllerDelegate {
  override public init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
    super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
    delegate = self

    // 自定义cell, [ConversationListModel.customType: 需要注册的自定义 UI 类型]
    // 自定义cell的注册字典需要在 viewDidLoad 之前完成初始化
    cellRegisterDic[1] = CustomConversationListCell.self
  }

  public required init?(coder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }

  override open func viewDidLoad() {
    super.viewDidLoad()
  }

  override open func deleteActionHandler(action: UITableViewRowAction, indexPath: IndexPath) {
    showSingleAlert(message: "override deleteActionHandler") {}
  }

  override open func topActionHandler(action: UITableViewRowAction, indexPath: IndexPath, isTop: Bool) {
    showSingleAlert(message: "override topActionHandler") {
      super.topActionHandler(action: action, indexPath: indexPath, isTop: isTop)
    }
  }

  //  父类加载完数据后会调用此方法,可在此对数据进行二次处理
  public func onDataLoaded() {
    guard let conversationList = viewModel.conversationListArray else { return
    }
    conversationList.forEach { model in
      model.customType = 1
    }
    tableView.reloadData()
  }
}

注意:onDataLoaded 方法调用时,表明父类已完成数据的加载,数据存放在 viewModel.conversationListArray 列表中,数据模型定义如下:

swift/* 
    会话列表数据模型 ConversationListModel
    // customType: 自定义 UI 类型,其在注册会话列表 cell 时作为 key 与自定义 cell 进行绑定
    // localExtension: 本地扩展字段,可根据业务需求添加数据,与 customType 结合可实现多种自定义 cell 的展示
*/
@objcMembers
public class ConversationListModel: NSObject {
  public var recentSession: NIMRecentSession?

  public var userInfo: User?
  public var teamInfo: NIMTeam?
  public var customType = 0
  public var localExtension: [String: Any]?
  override public init() {
    super.init()
  }
}

需要在 viewDidLoad 之前完成会话列表 cell 注册字典(cellRegisterDic)的初始化,cellRegisterDic 的类型为 [Int : NEBaseConversationListCell.Type], 其中 key 对应会话列表数据模型中的 customType,需要在此处与其对应的自定义 UI 类型进行绑定,从而实现不同类型的自定义单元格的对应展示。

例如在用户头像下添加小标,如下图所示:

默认 自定义后
未隐藏标题栏.png 小标.png

自定义标题栏(navigationView)

  • 示例代码(Swift)

    swiftopen class CustomConversationController: ConversationController {
      override public func viewDidLoad() {
        // 实现协议(重写tabbar点击事件)
        navigationView.delegate = self
    
        // 自定义会话列表标题、图标、间距
        navigationView.brandBtn.setTitle("消息", for: .normal)
        navigationView.brandBtn.setImage(nil, for: .normal)
        navigationView.brandBtn.layoutButtonImage(style: .left, space: 0)
    
        // 自定义添加按钮图标
        navigationView.addBtn.setImage(UIImage.ne_imageNamed(name: "noNeed_notify"), for: .normal)
    
        ...
    
        super.viewDidLoad()
      }
    
      // 通过继承方式重写次最右侧按钮点击事件, 这种方式会覆盖配置项中的点击事件
      override open func searchAction() {
        // searchAction
      }
    
      // 通过继承方式重写最右侧按钮点击事件, 这种方式会覆盖配置项中的点击事件
      override open func didClickAddBtn() {
        showSingleAlert(message: "override didClickAddBtn") {
          // didClickAddBtn
        }
      }
    }
    

    上述示例代码中 navigationView 为会话列表页面的标题栏视图,用户可自定义其中的 UI 元素,包括但不限于标题、标题图标、搜索按钮及其点击事件和添加按钮及其点击事件。

  • 效果对比

    默认 自定义后
    未隐藏标题栏.png 按钮.png

会话列表页顶部扩展视图

例如,可以在会话列表顶部增加提示条。

  • 示例代码(Swift)

    swiftpublic class CustomView: UIView {
      public let btn = UIButton()
    
      override public init(frame: CGRect) {
        super.init(frame: frame)
        btn.translatesAutoresizingMaskIntoConstraints = false
        btn.addTarget(self, action: #selector(tapView), for: .touchUpInside)
        btn.setTitle("按钮", for: .normal)
        btn.backgroundColor = .red
        addSubview(btn)
        NSLayoutConstraint.activate([
          btn.topAnchor.constraint(equalTo: topAnchor),
          btn.bottomAnchor.constraint(equalTo: bottomAnchor),
          btn.widthAnchor.constraint(equalToConstant: 200),
          btn.centerXAnchor.constraint(equalTo: centerXAnchor),
        ])
      }
    
      required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
      }
    
      @objc func tapView() {
        print("点击了自定义按钮")
      }
    }
    
    open class CustomConversationController: ConversationController {
      public lazy var customTopView: CustomView = {
        let view = CustomView(frame: CGRect(x: 0, y: 10, width: NEConstant.screenWidth, height: 40))
        view.backgroundColor = .blue
        return view
      }()
    
      override public init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
      }
    
      public required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
      }
    
      override public func viewDidLoad() {
        // 顶部bodyTopView中添加自定义view(需要设置bodyTopView的高度)
        customTopView.btn.setTitle("通过重写方式添加", for: .normal)
        bodyTopView.addSubview(customTopView)
        bodyTopViewHeight = 80
    
        // 自定义占位图文案、背景图片
        emptyView.setEmptyImage(image: UIImage())
        emptyView.settingContent(content: "")
        ...
        super.viewDidLoad()
      }
    
      // 通过继承方式重写次最右侧按钮点击事件, 这种方式会覆盖配置项中的点击事件
    override open func searchAction() {
      bodyTopViewHeight = 80
      bodyBottomViewHeight = 80
    }
    
    // 通过继承方式重写最右侧按钮点击事件, 这种方式会覆盖配置项中的点击事件
    override open func didClickAddBtn() {
      bodyTopViewHeight = 0
      bodyBottomViewHeight = 0
    }
    }
    

    示例代码中 bodyTopView 为会话列表页顶部预留的扩展视图,bodyTopViewHeight 为该扩展视图的高度,更改此变量会刷新页面布局。

  • 效果对比

    默认 自定义后
    未隐藏标题栏.png 顶部扩展.png
此文档是否对你有帮助?
有帮助
去反馈
  • 自定义功能描述
  • UI 元素自定义
  • 界面布局自定义
  • 通过配置项自定义 UI 示例
  • 隐藏标题栏
  • 修改会话名称字体颜色和大小
  • 通过源码自定义 UI 示例
  • 自定义单元格(TableviewCell)
  • 自定义标题栏(navigationView)
  • 会话列表页顶部扩展视图