关于云信聊天页面的分析
2020-02-11 本文已影响0人
曾柏超
具体文档请参考 云信文档
目录
- NIMSessionConfigurator 解耦 NIMSessionViewController 的方式
- 聊天页面设置头像实现
- 关于cell
- 关于tableView 的frame
- 关于数据源
- 关于消息的扩展
/*
NIMSessionViewController 类关系图
.........................................................................
. .
. .
. . | ---> [NIMSessionDatasource]
. .
. | ---> [NIMSessionInteractor] --> |
.
. | ---> [NIMSessionLayout]
.
↓
[NIMSessionViewController]-------> [NIMSessionConfigurator] -----> |
| (把tableView的数据源和cell 的样式的代码抽取出来了)
|
|
|
↓ | ---> [NIMSessionTableAdapter]
[UITableView] .
↑ .
. .
. .
.......................................................................
*/
0. 关于 NIMSessionConfigurator 解耦 NIMSessionViewController 的方式
@implementation NIMSessionViewController
- (void)setupConfigurator
{
_configurator = [[NIMSessionConfigurator alloc] init];
[_configurator setup:self];
BOOL needProximityMonitor = [self needProximityMonitor];
[[NIMSDK sharedSDK].mediaManager setNeedProximityMonitor:needProximityMonitor];
}
@end
一.设置头像
@interface NIMAvatarImageView()
@property (nonatomic,strong) UIImageView *imageView;
@end
@implementation NIMAvatarImageView
- (void)setAvatarByMessage:(NIMMessage *)message
{
NIMKitInfoFetchOption *option = [[NIMKitInfoFetchOption alloc] init];
option.message = message;
NSString *from = nil;
if (message.messageType == NIMMessageTypeRobot)
{
NIMRobotObject *object = (NIMRobotObject *)message.messageObject;
if (object.isFromRobot)
{
from = object.robotId;
}
}
if (!from)
{
from = message.from;
}
NIMKitInfo *info = [[NIMKit sharedKit] infoByUser:from option:option];
NSURL *url = info.avatarUrlString ? [NSURL URLWithString:info.avatarUrlString] : nil;
[self nim_setImageWithURL:url placeholderImage:info.avatarImage];
}
@end
二. 关于cell
cell 的代码全部封装在 NIMSessionTableAdapter 和 NIMMessageCellFactory
@implementation NIMSessionTableAdapter
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = nil;
id model = [[self.interactor items] objectAtIndex:indexPath.row];
if ([model isKindOfClass:[NIMMessageModel class]]) {
cell = [self.cellFactory cellInTable:tableView
forMessageMode:model];
[(NIMMessageCell *)cell setDelegate:self.delegate];
[(NIMMessageCell *)cell refreshData:model];
}
else if ([model isKindOfClass:[NIMTimestampModel class]])
{
cell = [self.cellFactory cellInTable:tableView
forTimeModel:model];
}
else
{
NSAssert(0, @"not support model");
}
return cell;
}
@end
@implementation NIMMessageCellFactory
- (NIMMessageCell *)cellInTable:(UITableView*)tableView
forMessageMode:(NIMMessageModel *)model
{
id<NIMCellLayoutConfig> layoutConfig = [[NIMKit sharedKit] layoutConfig];
NSString *identity = [layoutConfig cellContent:model];
NIMMessageCell *cell = [tableView dequeueReusableCellWithIdentifier:identity];
if (!cell) {
NSString *clz = @"NIMMessageCell";
[tableView registerClass:NSClassFromString(clz) forCellReuseIdentifier:identity];
cell = [tableView dequeueReusableCellWithIdentifier:identity];
}
return (NIMMessageCell *)cell;
}
- (NIMSessionTimestampCell *)cellInTable:(UITableView *)tableView
forTimeModel:(NIMTimestampModel *)model
{
NSString *identity = @"time";
NIMSessionTimestampCell *cell = [tableView dequeueReusableCellWithIdentifier:identity];
if (!cell) {
NSString *clz = @"NIMSessionTimestampCell";
[tableView registerClass:NSClassFromString(clz) forCellReuseIdentifier:identity];
cell = [tableView dequeueReusableCellWithIdentifier:identity];
}
[cell refreshData:model];
return (NIMSessionTimestampCell *)cell;
}
@end
三. 关于tableView 的frame
@implementation NIMSessionLayoutImpl
- (void)adjustTableView
{
//输入框是否弹起
BOOL inputViewUp = NO;
switch (self.inputView.status)
{
case NIMInputStatusText:
inputViewUp = [NIMKitKeyboardInfo instance].isVisiable;
break;
case NIMInputStatusAudio:
inputViewUp = NO;
break;
case NIMInputStatusMore:
case NIMInputStatusEmoticon:
inputViewUp = YES;
default:
break;
}
self.tableView.userInteractionEnabled = !inputViewUp;
CGRect rect = self.tableView.frame;
//tableview 的位置
UIView *superView = self.tableView.superview;
UIEdgeInsets safeAreaInsets = UIEdgeInsetsZero;
if (@available(iOS 11.0, *))
{
safeAreaInsets = superView.safeAreaInsets;
}
CGFloat containerSafeHeight = self.tableView.superview.frame.size.height - safeAreaInsets.bottom;
rect.size.height = containerSafeHeight - self.inputView.toolBar.nim_height;
//tableview 的内容 inset
UIEdgeInsets contentInsets = UIEdgeInsetsZero;
CGFloat visiableHeight = 0;
if (@available(iOS 11.0, *))
{
contentInsets = self.tableView.adjustedContentInset;
}
else
{
contentInsets = self.tableView.contentInset;
}
//如果气泡过少,少于总高度,输入框视图需要顶到最后一个气泡的下面。
visiableHeight = visiableHeight + self.tableView.contentSize.height + contentInsets.top + contentInsets.bottom;
visiableHeight = MIN(visiableHeight, rect.size.height);
rect.origin.y = containerSafeHeight - visiableHeight - self.inputView.nim_height;
rect.origin.y = rect.origin.y > 0? 0 : rect.origin.y;
BOOL tableChanged = !CGRectEqualToRect(self.tableView.frame, rect);
if (tableChanged)
{
[self.tableView setFrame:rect];
[self.tableView nim_scrollToBottom:YES];
}
}
@end
四. 关于数据源
@implementation NIMSessionMsgDatasource
- (NSArray<NIMMessageModel *> *)modelsWithMessages:(NSArray<NIMMessage *> *)messages
{
NSMutableArray *array = [[NSMutableArray alloc] init];
for (NIMMessage *message in messages) {
NIMMessageModel *model = [[NIMMessageModel alloc] initWithMessage:message];
[array addObject:model];
}
return array;
}
@end
五. 关于消息的扩展
@implementation NIMSessionInteractorImpl
#pragma mark - 消息收发接口
- (void)sendMessage:(NIMMessage *)message
{
[[[NIMSDK sharedSDK] chatManager] sendMessage:[self addExt:message] toSession:_session error:nil];
}
- (NIMMessage *)addExt:(NIMMessage *)msg
{
NSDictionary *ext = @{
@"name": name,
@"sex": sex,
};
msg.remoteExt = ext;
NSLog(@"msg.remoteExt---%@",msg.remoteExt);
return msg;
}
@end