Skip to content
能力中心
产品中心
应用市场
WebOffice
开发者后台

自定义搜索界面

协作中台SDK 提供了搜索页面的自定义能力,包括新增搜索分类、移除默认搜索分类/修改排序/修改名称、修改UI效果等。通过配置接口、实现自定义协议两种方式来对搜索界面进行自定义。

配置方式

可以通过配置方式完成搜索界面的样式自定义,搜索界面配置定义在 KIMSearchConfig 类中。

接口定义

KIMSearchConfig

属性类型说明
inputTextFontUIFont搜索输入框字体。
inputTextColorUIColor搜索输入框字体颜色。
inputTextPlaceholderNSAttributedString搜索输入框提示。
inputTextFieldBackgroundColorUIColor搜索输入框背景颜色。
inputTextFieldInsetsUIEdgeInsets?搜索输入框边距。
tabTextFontUIFont搜索tab标题字体。
tabTextColorUIColor搜索tab标题字体颜色。
tabTextSelectedColorUIColor搜索ab标题字体处于选中状态时的颜色。
tabBackgroundColorUIColor搜索tab选中时的背景颜色。
tabBarBackgroundColorUIColor搜索tab栏背景颜色。
resultHighlightColorUIColor?搜索结果高亮色。
tabIndicatorColorUIColor搜索tab选中标识颜色。
tabBarDividerLineColorUIColor搜索栏分割线颜色。

协议方式

可以通过设置搜索视图控制器的页面代理并实现相关协议方法来完成搜索界面的自定义,自定义协议定义在 KIMSearchViewControllerDelegate 中。

接口定义

KIMSearchViewControllerDelegate

方法参数返回值说明
searchViewController(_:configTitleView:)• controller: KIMSearchViewController
搜索页面视图控制器。
• titleView: KIMNavigationTitleView
标题视图。
Void配置搜索页面导航栏标题视图。可实现该方法,通过 titleView 参数获取导航栏标题视图控件,对标题视图控件进行配置,如修改导航栏视图背景颜色。
searchViewController(tabSettingViewFor:)• controller: KIMSearchViewController
搜索页面视图控制器。
UIView?
设置视图。
返回搜索分类栏右侧设置视图。实现该方法返回搜索分类栏右侧设置视图,内部会把返回的视图放到搜索分类栏的右边,用于设置场景入口拓展,如添加筛选入口,tab排序按钮等。
searchViewController(_:configSearchTextField:)• controller: KIMSearchViewController
搜索页面视图控制器。
• textField: UITextField
搜索输入框控件。
Void配置搜索输入框。如果需要对搜索输入框做轻量定制化,建议使用配置接口KIM.searchModule.searchConfig 进行设置。当配置接口满足不了搜索输入框的定制化需求时,可以实现该方法,通过 textField 参数对搜索输入框控件进行修改,如设置textField.leftView 等。
searchViewController(_:updateSearchFilters:)• controller: KIMSearchViewController
搜索页面视图控制器。
• filters: [KIMSearchFilterItem]
搜索筛选条件。
[KIMSearchFilterItem]
新的搜索条件。
更新搜索筛选条件。可以实现该方法返回自身业务需要的搜索条件,当触发搜索时,内部只负责把新的 [KIMSearchFilterItem] 透传到每个 KIMSearchTabsearch(keyword: String, filters: [KIMSearchFilterItem]?, callback: @escaping (_ status: KIMSearchStatus, _ error: NSError?) -> Void) 方法中的 filters 参数。
searchViewController(_:updateSearchTabs:)• controller: KIMSearchViewController
搜索页面视图控制器。
• tabs: [KIMSearchTab]
默认搜索分类。
[KIMSearchTab]
修改后的数据。
更新搜索分类Tab。搜索分类栏刷新时会调用该方法,可实现该方法对搜索分类Tab进行二次加工。tabs 为默认搜索分类,可基于默认 tabs 进行改造(如修改排序、插入、删除元素)返回新的 KIMSearchTab 数组。
注意:tabs 参数的第一个元素为 KIMSearchMergeTab 类型对象,代表 “全部” Tab,如果需要对 “全部” Tab里面的属性或元素进行修改,你可以把他转成 KIMSearchMergeTab 类型,然后修改相关属性,如修改 KIMSearchMergeTab 的类型为[KIMSearchMergeSubItem]subTabs 属性新增或删除 “全部” Tab 下的聚合子项。
调用 KIMSearchViewControllerreloadSearchTabs 方法可刷新搜索分类栏。

KIMSearchTab 为搜索分类tab协议,定义如下:

方法参数返回值说明
typeString搜索项类型,作为当前搜索项的唯一标记。
titleString搜索项在分类栏上展示的标题。
contentViewUIView搜索项展示的内容视图。该视图会添加到当前分类Tab下,在搜索页选中该分类Tab时,会展示出来。
attributedPlaceholderNSAttributedString切换到当前搜索项时搜索文本输入框所展示的提示文本。
search• keyword: String
搜索关键字。
• filters: [KIMSearchFilterItem]?
过滤条件。
• callback: (_ status: KIMSearchStatus, _ error: NSError?) -> Void
搜索结果回调。
• status: 搜索状态。
• error: 错误信息,当搜索失败是可以传入。
Void实现该方法监听搜索操作,当输入框输入搜索文本或手动调用 KIMSearchViewControllersearch(keyword: String) 时会调用该代理方法,你可以在方法中执行搜索流程如:发起搜索请求。
注意:内部页面根据 callbackstatus 回调参数来展示状态视图。
• notSearch:未搜索,展示未搜索状态视图。
• success:搜索成功,展示 contentView 方法返回的视图。
• finish:搜索完成无更多数据,展示 contentView 方法返回的视图。
• searching:搜索中,展示搜索中加载视图。
• empty:搜索结果为空,展示搜索结果为空提示视图。
• failure:搜索失败,展示搜索失败状态视图。
loadingViewUIView?搜索中加载视图。实现该方法返回自定义的加载视图,该视图会添加到 contentView 上。不实现该方法时内部默认展示 KIMSearchLoadingView,返回为nil时,不展示默认视图,可自己实现相关提示逻辑。
emptyViewUIView?搜索结果为空提示视图。实现该方法返回自定义的加载视图,该视图会添加到 contentView 上。不实现该方法时内部默认展示 KIMSearchStatusView,返回为nil时,不展示默认视图,可自己实现相关提示逻辑。
errorViewUIView?搜索失败提示视图。实现该方法返回自定义的加载视图,该视图会添加到 contentView 上。不实现该方法时内部默认展示 KIMSearchStatusView,返回为nil时,不展示默认视图,可自己实现相关提示逻辑。
emptyInputViewUIView?未搜索时提示视图。实现该方法返回自定义的加载视图,该视图会添加到 contentView 上。不实现该方法时内部默认展示 KIMSearchStatusView,返回为nil时,不展示默认视图,可自己实现相关提示逻辑。

KIMSearchMergeSubItem 为搜索聚合项“全部”Tab下的每个合并子项协议,定义如下:

方法参数返回值说明
itemTypeString搜索子项类型,用来标记该聚合子项。
itemTitleString该子项在“全部” Tab下展示的标题。
moreTextString?该子项搜索结果最后一行 "更多" cell所显示的文本内容,设置为nil时则不显示 “更多” cell。
didSelectedCell• cellModel: KIMSearchMergeCellModel
搜索结果cell模型,对应 searchForMerge(keyword: String, callback: @escaping (_ result: KIMSearchMergeResult?, _ error: NSError?) -> Void) 方法回调结果 result 中的 cellModel 信息。
• indexPath: IndexPath
当前列表索引。
Void搜索结果Cell点击事件。实现该方法响应cell的点击事件。
didSelectedMoreCellVoid你可以实现该方法自定义“更多” Cell点击事件,不实现时该方法时,点击“更多” Cell后默认滚动到对应的搜索分类Tab上,效果同调用 KIMSearchViewControllerscrollToTab(tab: KIMSearchTab) 方法。
searchForMerge• keyword: String
搜索关键字。
• filters: [KIMSearchFilterItem]?
过滤条件。
• callback: (_ result: KIMSearchMergeResult?, _ error: NSError?) -> Void
搜索结果回调。
• result: 搜索成功结果。
• error: 错误信息,当搜索失败是可以传入。
Void触发聚合子项搜索操作。实现该方法监听搜索操作,当输入框输入搜索文本或手动调用 KIMSearchViewControllersearch(keyword: String) 时会调用该代理方法,你可以在方法中执行搜索流程如:发起搜索请求。
注意:内部页面根据 callback 的回调结果来展示搜索数据,KIMSearchMergeResult 中的 cellModels信息中需要包含要展示的 UITableViewCell 类型。

自定义示例

样式配置

搜索页面样式配置需要在搜索页面加载之前进行,可以通过修改 KIMSearchConfig 中定义的各种属性达到个性化样式配置。

默认搜索框自定义搜索框

代码示例

Swift
// 1. 继承搜索视图控制器。
class CustomSearchViewController: KIMSearchViewController, KIMSearchViewControllerDelegate {

    // 2. 重写初始化方法,设置页面自定义协议代理。
    required init() {
        super.init()
        // 设置页面自定义协议代理。
        self.delegate = self

        // 设置全局搜索输入框样式
        // 设置搜索tab标题字体
        KIM.searchModule.searchConfig.tabTextColor = .black
        // 设置搜索tab标题字体处于选中状态时的颜色
        KIM.searchModule.searchConfig.tabTextSelectedColor = .init(hex: "#582263")
        // 设置搜索tab选中标识颜色
        KIM.searchModule.searchConfig.tabIndicatorColor = .init(hex: "#582263")
        // 设置输入框placeholder
        // 注意:placeholder需要通过全局配置,不能通过configSearchTextField配置,同时需要写在super.init()之后
        KIM.searchModule.searchConfig.inputTextPlaceholder = NSAttributedString(
            string: "搜索",
            attributes: [.foregroundColor: UIColor.white, .backgroundColor: UIColor.init(hex: "#582263")]
        )
    }

    // 3.实现 KIMSearchViewControllerDelegate 相关协议方法。

    // 搜索输入框配置
    func searchViewController(_ controller: WOASDK.KIMSearchViewController, configSearchTextField textField: UITextField) {
        // 注意:输入框图标需要在此处设置
        // 设置输入框左侧图标
        let customLeftView = UIView()
        customLeftView.addSubview(customImageView())
        textField.leftView = customLeftView
        textField.leftViewMode = .always
    }
}

自定义默认搜索分类

搜索界面默认展示了全部、聊天记录、云文档、机器人、联系人等搜索分类,可通过实现KIMSearchViewControllerDelegateupdateSearchTabs 协议方法来自定义默认搜索分类,如对搜索分类进行新增、删除、修改排序等操作。

默认自定义

代码示例

Swift
// 1. 继承搜索视图控制器。
class CustomSearchViewController: KIMSearchViewController, KIMSearchViewControllerDelegate {

   // 2. 重写初始化方法,设置页面自定义协议代理。
   required init() {
        super.init()
        // 设置页面自定义协议代理。
        self.delegate = self
    }

    // 3.实现 KIMSearchViewControllerDelegate 相关协议方法。

    // 更新搜索分类Tab。
    func searchViewController(_ controller: KIMSearchViewController, updateSearchTabs tabs: [KIMSearchTab]) -> [KIMSearchTab] {
        // 全部
        let allTab = tabs.first { $0.type == KIMSearchType.all.rawValue }
        // 联系人
        let contactTab = tabs.first { $0.type == KIMSearchType.contacts.rawValue }     // 群聊
        let groupTab = tabs.first { $0.type == KIMSearchType.group.rawValue }
        // 聊天文件
        let chatFileTab = tabs.first { $0.type == KIMSearchType.file.rawValue }
          
        // 返回新的tab数组
        var newTabs = [contactTab, allTab, groupTab, chatFileTab].compactMap { $0 }
        return newTabs
    }
}

新增搜索分类

通过实现KIMSearchViewControllerDelegateupdateSearchTabs 协议方法插入自定义的KIMSearchTab来新增搜索分类。

代码示例

  1. 继承自KIMSearchViewController 实现 updateSearchTabs 协议方法插入自定义搜索分类。
Swift
// 1. 实现自定义搜索数据模型
class SearchModel: KIMSearchModel {
    
    var mainTitle: String?
    var subTitle: String?
    
    init(mainTitle: String?, subTitle: String?) {
        self.mainTitle = mainTitle
        self.subTitle = subTitle
    }
}

// 2. 继承搜索视图控制器。
class CustomSearchViewController: KIMSearchViewController, KIMSearchViewControllerDelegate {

   // 自定义搜索分类实例。
   lazy var customSearchTab: CustomSearchTab = {
        let tab = CustomSearchTab()
        return tab
    }()

   // 3. 重写初始化方法,设置页面自定义协议代理。
   required init() {
        super.init()
        // 设置页面自定义协议代理。
        self.delegate = self
    }

    // 4.实现 KIMSearchViewControllerDelegate 相关协议方法。

    // 更新搜索分类Tab。
    func searchViewController(_ controller: KIMSearchViewController, updateSearchTabs tabs: [KIMSearchTab]) -> [KIMSearchTab] {
        var newTabs = tabs
        // 在搜索分类tab中插入新增的自定义搜索分类。
        newTabs.insert(customSearchTab, at: 1)

        // 在 “全部” tab 中插入新增的自定义搜索分类。
        if let mergeTab = newTabs.first as? KIMSearchMergeTab {
            mergeTab.subTabs.insert(customSearchTab, at: 0)
        }

        return newTabs
    }
}
  1. 实现 KIMSearchTab 协议,作为搜索分类栏的其中一个tab。
Swift
// 自定义搜索分类tab
class CustomSearchTab: NSObject, UITableViewDelegate, UITableViewDataSource {

    /// 内容 contentView
    lazy var tableView: UITableView = {
        let tableView = UITableView(frame: .zero, style: .grouped)
        tableView.rowHeight = UITableView.automaticDimension
        tableView.dataSource = self
        tableView.delegate = self
        if #available(iOS 15.0, *) {
            tableView.sectionHeaderTopPadding = 0
        }
        tableView.register(CustomSearchCell.self, forCellReuseIdentifier: NSStringFromClass(CustomSearchCell.self))
        return tableView
    }()

    // 搜索数据: 当前筛选后的搜索结果
    var filteredSearchResults: [SearchModel] = []
    // 搜索数据: 全量的搜索数据
    var allSearchData: [SearchModel] = []

    public override init() {
        super.init()
    }

    open func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return filteredSearchResults.count
    }

    open func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let model = self.filteredSearchResults[indexPath.row]
        let cell = tableView.dequeueReusableCell(withIdentifier: NSStringFromClass(CustomSearchCell.self), for: indexPath)
        let searchCell = cell as? CustomSearchCell
        searchCell?.configCell(searchModel: model)
        return cell
    }

}

// 实现 KIMSearchTab 协议
extension CustomSearchTab: KIMSearchTab {

    var contentView: UIView {
        return self.tableView
    }

    var title: String {
        return "自定义"
    }

    var type: String {
        return "custom_1"
    }

    var attributedPlaceholder: NSAttributedString? {
        return NSAttributedString(string: "自定义搜索提示")
    }

    var emptyInputView: UIView? {
        return customEmptyInputView()
    }

    func search(keyword: String, filters: [WOASDK.KIMSearchFilterItem]?, callback: @escaping (WOASDK.KIMSearchStatus, NSError?) -> Void) {
        // 搜索状态回调
        callback(.searching, nil)

        // 可以在此处自定义搜索逻辑
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
            var filteredData: [SearchModel] = []

            // 过滤包含 keyword 的项
            for item in self.allSearchData {
                if let context = item.mainTitle, context.contains(keyword) {
                    filteredData.append(item)
                }
            }
            self.filteredSearchResults = filteredData
            self.tableView.reloadData()

            // 搜索状态回调
            callback(.finish, nil)
        }
    }
}
  1. 实现 KIMSearchMergeSubItem 协议,支持展示在“全部”tab下作为聚合分类。
Swift
// 实现 KIMSearchMergeSubItem 协议
extension CustomSearchTab: KIMSearchMergeSubItem {

    var itemTitle: String {
        return "自定义"
    }

    var itemType: String {
        return "custom_1"
    }

    var moreText: String? {
        return "更多xxx结果"
    }

    func searchForMerge(keyword: String, filters: [KIMSearchFilterItem]?, callback: @escaping (KIMSearchMergeResult?, NSError?) -> Void) {
        // 模拟搜索结果请求:需要自定义搜索聚合逻辑
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
            // 可以在此处自定义搜索逻辑
            var cellModels: [KIMSearchMergeCellModel] = []
            var maxCount = 0
            for item in self.allSearchData {
                // 控制聚合中的搜索结果数量
                if maxCount >= 3 {
                    break
                }
                // 过滤包含 keyword 的项
                if let context = item.mainTitle, context.contains(keyword) {
                    let cellModel = KIMSearchMergeCellModel.init(cellType: CustomSearchCell.self, data: item)
                    cellModels.append(cellModel)
                    maxCount += 1
                }
            }
            // 搜索状态回调
            callback(.init(hasMore: true, cellModels: cellModels), nil)
        }
    }
}
  1. 在“全部”tab中插入的自定义Cell实现 KIMSearchMergeCell 协议。
Swift
class CustomSearchCell: UITableViewCell {
    var mainLabel: UILabel = UILabel()
    var subLabel: UILabel = UILabel()
    // ....

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

        // ......
    }

    func configCell(searchModel: SearchModel) {
        self.mainLabel.text = searchModel.mainTitle
        self.subLabel.text = searchModel.subTitle
    }
}

// 实现 KIMSearchMergeCell 协议。
extension CustomSearchCell: KIMSearchMergeCell {

    public func setSearchMergeCellModel(_ cellModel: KIMSearchMergeCellModel)     {
        guard let searchModel = cellModel.data as? SearchModel else { return }
        configCell(searchModel: searchModel)
    }
}

配置搜索分类栏右侧设置视图

通过实现 KIMSearchViewControllerDelegatetabSettingViewFor 方法配置搜索分类栏右侧设置视图,用于添加额外业务入口的场景,如排序设置入口、筛选设置入口等场景。

代码示例

Swift
// 1. 继承搜索视图控制器。
class CustomSearchViewController: KIMSearchViewController, KIMSearchViewControllerDelegate {

   // 2. 重写初始化方法,设置页面自定义协议代理。
   required init() {
        super.init()
        // 设置页面自定义协议代理。
        self.delegate = self
    }

    // 3.实现 KIMSearchViewControllerDelegate 相关协议方法。

    // 返回搜索分类栏右侧设置视图。
    func searchViewController(tabSettingViewFor controller: KIMSearchViewController) -> UIView? {
        // 配置按钮
        let tabSettingButton = UIButton()
        tabSettingButton.addTarget(self, action: #selector(tabSettingButtonTap), for: .touchUpInside)
        // 添加按钮到右侧视图,需要设置好宽高
        let tabSettingView = UIView()
        tabSettingView.addSubview(tabSettingButton)
        return tabSettingView
    }

    // 实现右侧按钮点击事件
    @objc func tabSettingButtonTap() {
        //在此处可以自定义实现tab项的筛选设置、排序设置等
    }
}

全部中单独配置分类

通过实现 KIMSearchViewControllerDelegateupdateSearchTabs 方法,单独配置搜索分类栏中"全部"这一tab的显示,用于实现聚合搜索中的自定义样式显示场景。

代码示例

Swift
// 1. 继承搜索视图控制器。
class CustomSearchViewController: KIMSearchViewController, KIMSearchViewControllerDelegate {

    // 自定义搜索分类实例。
    var customSearchTab = CustomSearchTab()
    // 自定义更多搜索分类实例。
    var customMoreTab = CustomSearchTab()
    // ....

   // 2. 重写初始化方法,设置页面自定义协议代理。
   required init() {
        super.init()
        // 设置页面自定义协议代理。
        self.delegate = self
    }

    // 3.实现 KIMSearchViewControllerDelegate 相关协议方法。

    // 更新搜索分类Tab。
    func searchViewController(_ controller: KIMSearchViewController, updateSearchTabs tabs: [KIMSearchTab]) -> [KIMSearchTab] {
        var newTabs = tabs
        // 在 “全部” tab 中插入新增的自定义搜索分类。
        if let mergeTab = newTabs.first as? KIMSearchMergeTab {
            var subTabs: [KIMSearchMergeSubItem] = []
            // 在 “全部” tab 中插入自定义搜索分类
            subTabs.append(customSearchTab)
            subTabs.append(customMoreTab)
            // 在 “全部” tab 中插入通讯录、群聊、聊天文件分类。
            for subTab in mergeTab.subTabs {
                if subTab.itemType == KIMSearchType.contacts.rawValue ||
                    subTab.itemType == KIMSearchType.group.rawValue ||
                    subTab.itemType == KIMSearchType.file.rawValue {
                    subTabs.append(subTab)
                }
            }
            mergeTab.subTabs = subTabs
        }
        return newTabs
    }
}

全局替换视图控制器

如果子类化会话列表视图控制器后,希望SDK内部入口在初始化搜索页面时都使用子类类型,可以通过设置搜索视图控制器的子类类型 searchViewControllerType 来达到效果。

代码示例

Swift
KIM.searchModule.searchViewControllerType = CustomSearchViewController.self