跳到主要内容

自适应双栏会话容器

提示

IMKit SDK 从 5.48.0 版本开始提供 RCConversationContainerViewController,用于 iPhone Duo 等需要自适应单双栏布局的场景。

RCConversationContainerViewController 统一管理会话列表页面和会话页面及其导航。空间和系统布局条件允许时,会话列表与会话页面并排显示;空间不足时,自动切换为单栏,在列表和会话页面之间导航。

双栏布局下,未打开会话时详情栏显示占位页。单双栏切换时,容器保留当前会话页面及其后续页面的导航状态。

初始化​

使用 initWithConversationListViewController: 传入会话列表控制器,创建会话容器。您可以传入 RCConversationListViewController 或其子类。

接口原型​

Objective C
- (instancetype)initWithConversationListViewController:(RCConversationListViewController *)listViewController;

参数说明​

参数类型说明
listViewControllerRCConversationListViewController会话列表控制器,必须尚未属于其他父控制器。

示例代码​

以下代码在 UITabBarController 子类中执行,将会话容器作为一个 Tab 页面。其他 Tab 可按应用现有方式配置。

Objective C
NSArray *conversationTypes = @[@(ConversationType_PRIVATE),
@(ConversationType_GROUP),
@(ConversationType_SYSTEM)];
RCConversationListViewController *listViewController =
[[RCConversationListViewController alloc]
initWithDisplayConversationTypes:conversationTypes
collectionConversationType:nil];

RCConversationContainerViewController *container =
[[RCConversationContainerViewController alloc]
initWithConversationListViewController:listViewController];
container.tabBarItem.title = @"消息";
self.viewControllers = @[container];
提示
  • 双栏布局需要 iOS 14 及以上版本,更低版本始终使用单栏布局。
  • 容器内部已管理导航控制器,应直接放入 Tab 或其他父容器,不要在外部再次包装 UINavigationController。
  • 容器的初始化、配置和页面操作均须在主线程执行。

打开会话​

使用默认列表点击行为​

如果没有重写会话列表的 onSelectedTableRow:conversationModel:atIndexPath: 方法,接入容器后,点击会话会由 SDK 自动创建并呈现会话页面。

如需通过已有的 RCConversationModel 主动打开会话,可调用 showConversationModel:animated:。下文中的 container 为初始化时创建的会话容器,model 为目标会话的数据模型。

接口原型​

Objective C
- (void)showConversationModel:(RCConversationModel *)model animated:(BOOL)animated;

参数说明​

参数类型说明
modelRCConversationModel目标会话的数据模型。
animatedBOOL是否在支持动画的导航操作中使用过渡动画。

示例代码​

Objective C
[container showConversationModel:model animated:YES];

使用已配置的会话页面​

如果已重写列表点击事件,并自行创建、配置会话页面,可保留原有业务逻辑,将最终的 pushViewController:animated: 调用替换为列表的 showConversationViewController:animated:。

以下示例在 RCConversationListViewController 子类中重写点击事件。会话页面可替换为应用自定义的 RCConversationViewController 子类。

示例代码​

Objective C
- (void)onSelectedTableRow:(RCConversationModelType)conversationModelType
conversationModel:(RCConversationModel *)model
atIndexPath:(NSIndexPath *)indexPath {
RCConversationViewController *conversation =
[[RCConversationViewController alloc]
initWithConversationType:model.conversationType targetId:model.targetId];
conversation.channelId = model.channelId;
conversation.title = model.conversationTitle;
conversation.unReadMessage = model.unreadMessageCount;
conversation.enableNewComingMessageIcon = YES;
conversation.enableUnreadMessageIcon = YES;
[self showConversationViewController:conversation animated:YES];
}

showConversationViewController:animated: 在容器中会根据当前布局呈现页面;列表独立使用时,仍通过列表所属的导航控制器打开页面。自行处理呈现时,不要再调用默认点击实现,以免重复打开会话。已实现聚合会话等点击分支的应用,应保留原有分支处理,仅替换打开具体会话页面的动作。

搜索结果、通知等其他入口可以直接调用容器的 presentConversationViewController:animated:,传入已完成业务配置、尚未属于其他父控制器的会话页面。

Objective C
RCConversationViewController *conversation =
[[RCConversationViewController alloc]
initWithConversationType:ConversationType_PRIVATE targetId:@"targetId"];
conversation.title = @"会话标题";
[container presentConversationViewController:conversation animated:YES];
提示
  • 调用 showConversationModel:animated: 时,会话类型、会话 ID 和频道 ID 均与当前会话一致,则复用当前页面,并返回该会话的根页面。
  • 调用 presentConversationViewController:animated: 时,传入当前会话页面实例会返回该会话的根页面;传入不同实例会替换当前会话页面及其后续页面,即使两个实例的会话标识相同。列表的 showConversationViewController:animated: 在容器中使用同样的呈现规则。

定制化​

自定义会话页面​

您可以通过 conversationViewControllerFactory 配置会话页面的创建方式。默认列表点击和 showConversationModel:animated: 需要创建新页面时,会调用此回调。

回调应返回已完成业务配置、尚未属于其他父控制器的 RCConversationViewController 或其子类。返回 nil 表示取消本次打开操作。未设置回调时,由 SDK 创建和配置默认会话页面。

示例代码​

Objective C
container.conversationViewControllerFactory =
^RCConversationViewController *(RCConversationModel *model) {
RCConversationViewController *conversation =
[[RCConversationViewController alloc]
initWithConversationType:model.conversationType targetId:model.targetId];
conversation.channelId = model.channelId;
conversation.title = model.conversationTitle;
conversation.unReadMessage = model.unreadMessageCount;
conversation.enableNewComingMessageIcon = YES;
conversation.enableUnreadMessageIcon = YES;
return conversation;
};
提示

复用当前会话,或通过 showConversationViewController:animated:、presentConversationViewController:animated: 传入已配置页面时,不会调用 conversationViewControllerFactory。

自定义详情占位页​

通过 placeholderViewController 设置双栏布局中未打开会话时显示的页面。未设置时使用 SDK 默认占位页。

Objective C
UIViewController *placeholder = [[UIViewController alloc] init];
placeholder.view.backgroundColor = [UIColor whiteColor];
container.placeholderViewController = placeholder;

占位页必须尚未属于其他父控制器。当前未打开会话时,更换占位页会立即更新详情栏。

自定义导航控制器​

如果需要使用应用自定义的导航控制器或统一导航栏样式,可设置 navigationControllerFactory。此回调用于创建列表导航控制器,以及 iOS 14 及以上的详情导航控制器。

每次调用都须返回一个独立、尚未属于其他父控制器的导航控制器,并以 SDK 传入的 rootViewController 为根页面。

Objective C
container.navigationControllerFactory =
^UINavigationController *(UIViewController *rootViewController) {
UINavigationController *navigationController =
[[UINavigationController alloc] initWithRootViewController:rootViewController];
navigationController.navigationBar.tintColor = [UIColor blackColor];
return navigationController;
};
提示

navigationControllerFactory 必须在容器视图加载前设置,例如在将容器加入 UITabBarController 前完成配置。创建后的单双栏导航栈由 SDK 管理。

布局控制与状态监听​

容器根据当前可用空间、系统布局条件和布局代理的返回值决定是否展开。您可以设置 delegate,实现 RCConversationContainerViewControllerDelegate 中的可选方法。

方法说明
conversationContainer:shouldExpandForSize:返回 NO 时保持单栏;返回 YES 时允许 SDK 继续根据空间和系统条件判断,不保证一定展开。未实现时由 SDK 决定。
conversationContainer:didChangeExpanded:实际单双栏状态变化时回调。expanded 为 YES 表示列表与会话并排显示。

以下示例在实现了该代理协议的控制器中执行,仅在容器宽度大于高度时允许展开。该条件是应用的布局策略,实际布局仍由 SDK 和系统条件共同决定。

Objective C
container.delegate = self;
Objective C
- (BOOL)conversationContainer:(RCConversationContainerViewController *)container
shouldExpandForSize:(CGSize)size {
return size.width > size.height;
}

代理方法在主线程调用。size 为当前容器视图尺寸,尚未扣除安全区;展开判断可能在布局过程中多次调用。需要读取当前实际布局时,使用只读属性 expanded。

获取当前页面​

您可以通过以下属性读取容器管理的页面,或从页面查找所属的会话容器。

方法或属性说明
conversationListViewController初始化容器时传入的会话列表控制器。
currentConversationViewController当前会话页面;尚未打开或已关闭会话时为 nil。
containerForViewController:类方法,从指定控制器及其父控制器中查找最近的会话容器;未找到时返回 nil。