优化 XPRoomMessageContainerView 和 XPRoomMessageTableViewCell,改进消息处理逻辑,增加行高预计算方法,减少不必要的视图更新,提升性能和用户体验。同时,调整 UITableView 的约束更新方式,确保更高效的布局管理。
This commit is contained in:
@@ -108,27 +108,16 @@
|
||||
|
||||
// 新增方法优化约束更新
|
||||
- (void)rebuildNormalConstraints {
|
||||
[self.contentLabel mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
[self.contentLabel mas_updateConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.mas_equalTo(self.contentView);
|
||||
make.leading.mas_equalTo(self.contentView).offset(12);
|
||||
make.bottom.mas_equalTo(self.contentView).offset(-20);
|
||||
make.width.mas_equalTo(kRoomMessageMaxWidth);
|
||||
}];
|
||||
|
||||
[self.bubbleImageView mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
[self.bubbleImageView mas_updateConstraints:^(MASConstraintMaker *make) {
|
||||
make.edges.mas_equalTo(self.contentLabel).insets(UIEdgeInsetsMake(0, -10, 0, -10));
|
||||
}];
|
||||
|
||||
|
||||
// [self.bubbleImageView mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
// make.leading.mas_equalTo(8);
|
||||
// make.top.bottom.mas_equalTo(0);
|
||||
// make.trailing.mas_equalTo(-8);
|
||||
// }];
|
||||
//
|
||||
// [self.contentLabel mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
// make.edges.mas_equalTo(UIEdgeInsetsMake(4, 12, 4, 12));
|
||||
// }];
|
||||
}
|
||||
|
||||
#pragma mark - tool
|
||||
@@ -164,20 +153,28 @@
|
||||
|
||||
#pragma mark - Getters And Setters
|
||||
- (void)setMessageInfo:(XPMessageInfoModel *)messageInfo {
|
||||
if ([messageInfo.content isEqualToAttributedString:_messageInfo.content]) {
|
||||
// 更严格的比较,减少不必要的更新
|
||||
if (_messageInfo &&
|
||||
[messageInfo.content isEqualToAttributedString:_messageInfo.content] &&
|
||||
[messageInfo.bubbleImageUrl isEqualToString:_messageInfo.bubbleImageUrl] &&
|
||||
[messageInfo.boomImageUrl isEqualToString:_messageInfo.boomImageUrl]) {
|
||||
return;
|
||||
}
|
||||
|
||||
_messageInfo = messageInfo;
|
||||
if (messageInfo) {
|
||||
// 确保在设置attributedText之前先设置hasBubble属性
|
||||
self.contentLabel.hasBubble = ![NSString isEmpty:messageInfo.bubbleImageUrl];
|
||||
BOOL hasBubble = ![NSString isEmpty:messageInfo.bubbleImageUrl];
|
||||
if (self.contentLabel.hasBubble != hasBubble) {
|
||||
self.contentLabel.hasBubble = hasBubble;
|
||||
}
|
||||
|
||||
self.contentLabel.attributedText = messageInfo.content;
|
||||
|
||||
if (self.isLeftBigImage) {
|
||||
if (self.isLeftBigImage && messageInfo.boomImageUrl) {
|
||||
self.leftBigImageView.imageUrl = messageInfo.boomImageUrl;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
- (void)updateLayoutWithoutBubble:(BOOL)hasBubble layoutSize:(CGSize)size {
|
||||
@@ -216,12 +213,12 @@
|
||||
UIImage *cutImage = [image1 cropRightAndBottomPixels:2];
|
||||
self.bubbleImageView.image = [self resizableImage:cutImage];
|
||||
}];
|
||||
[self.bubbleImageView mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
[self.bubbleImageView mas_updateConstraints:^(MASConstraintMaker *make) {
|
||||
make.edges.mas_equalTo(self.contentLabel).insets(UIEdgeInsetsMake(-10, -10, -10, -10));
|
||||
}];
|
||||
} else {
|
||||
self.bubbleImageView.image = [UIImage imageWithColor:[DJDKMIMOMColor messageBubbleColor]];
|
||||
[self.bubbleImageView mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
[self.bubbleImageView mas_updateConstraints:^(MASConstraintMaker *make) {
|
||||
make.edges.mas_equalTo(self.contentLabel).insets(UIEdgeInsetsMake(0, -10, 0, -10));
|
||||
}];
|
||||
}
|
||||
|
@@ -210,9 +210,11 @@ NSString * const kRoomShowTopicKey = @"kRoomShowTopicKey";
|
||||
}
|
||||
|
||||
// 4. 超长消息处理逻辑
|
||||
BOOL needReloadData = NO;
|
||||
if (self.datasource.count > kRoomMessageMaxLength) {
|
||||
NSInteger removedCount = kRoomMessageMaxLength / 2;
|
||||
[self safelyRemoveMessages:removedCount];
|
||||
needReloadData = YES; // 标记需要重新加载数据
|
||||
}
|
||||
|
||||
// 5. 插入新消息
|
||||
@@ -230,7 +232,13 @@ NSString * const kRoomShowTopicKey = @"kRoomShowTopicKey";
|
||||
}
|
||||
[self updateAllDataSource:tempNewDatas];
|
||||
[self.incomingMessages removeAllObjects];
|
||||
|
||||
// 如果有删除操作,使用 reloadData;否则使用增量更新
|
||||
if (needReloadData) {
|
||||
[self.messageTableView reloadData];
|
||||
} else if (indexPaths.count > 0) {
|
||||
[self.messageTableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationNone];
|
||||
}
|
||||
|
||||
// 6. 滚动到指定位置或底部
|
||||
[self scrollToFirstLocationOrBottom];
|
||||
@@ -463,13 +471,16 @@ NSString * const kRoomShowTopicKey = @"kRoomShowTopicKey";
|
||||
return;
|
||||
}
|
||||
|
||||
BOOL needReloadData = NO;
|
||||
if (self.datasource.count > kRoomMessageMaxLength) {
|
||||
NSIndexSet *set = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, kRoomMessageMaxLength/2)];
|
||||
NSArray *needRemoveMsgArray = [self.datasource objectsAtIndexes:set];
|
||||
[self.datasource removeObjectsInArray:needRemoveMsgArray];
|
||||
needReloadData = YES; // 标记需要重新加载数据
|
||||
}
|
||||
|
||||
NSMutableArray *tempArray = @[].mutableCopy;
|
||||
NSMutableArray *indexPaths = @[].mutableCopy;
|
||||
@kWeakify(self);
|
||||
[self.incomingMessages enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
@kStrongify(self);
|
||||
@@ -482,13 +493,20 @@ NSString * const kRoomShowTopicKey = @"kRoomShowTopicKey";
|
||||
if (model) {
|
||||
[tempArray addObject:model];
|
||||
[self.datasource addObject:model];
|
||||
[indexPaths addObject:[NSIndexPath indexPathForRow:self.datasource.count - 1 inSection:0]];
|
||||
}
|
||||
}];
|
||||
|
||||
[self.incomingMessages removeAllObjects];
|
||||
|
||||
[self updateAllDataSource:tempArray];
|
||||
|
||||
// 如果有删除操作,使用 reloadData;否则使用增量更新
|
||||
if (needReloadData) {
|
||||
[self.messageTableView reloadData];
|
||||
} else if (indexPaths.count > 0) {
|
||||
[self.messageTableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationNone];
|
||||
}
|
||||
|
||||
//执行插入动画并滚动
|
||||
[self scrollToBottom:NO];
|
||||
@@ -514,7 +532,17 @@ NSString * const kRoomShowTopicKey = @"kRoomShowTopicKey";
|
||||
}
|
||||
if(source.count > 0){
|
||||
NSIndexPath *ip = [NSIndexPath indexPathForRow:source.count-1 inSection:0]; //取最后一行数据
|
||||
[self.messageTableView scrollToRowAtIndexPath:ip atScrollPosition:UITableViewScrollPositionBottom animated:animated]; //滚动到最后一行
|
||||
|
||||
// 优化滚动动画,减少与布局更新的冲突
|
||||
if (animated) {
|
||||
// 使用 dispatch_async 确保布局更新完成后再滚动
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self.messageTableView scrollToRowAtIndexPath:ip atScrollPosition:UITableViewScrollPositionBottom animated:YES];
|
||||
});
|
||||
} else {
|
||||
[self.messageTableView scrollToRowAtIndexPath:ip atScrollPosition:UITableViewScrollPositionBottom animated:NO];
|
||||
}
|
||||
|
||||
self.atCount = 0;
|
||||
self.atTipBtn.hidden = YES;
|
||||
[self.locationArray removeAllObjects];
|
||||
@@ -1282,14 +1310,33 @@ NSString * const kRoomShowTopicKey = @"kRoomShowTopicKey";
|
||||
|
||||
XPMessageInfoModel *model = [source xpSafeObjectAtIndex:indexPath.row];
|
||||
|
||||
// 如果 model 中有高度数据,使用 model 的高度
|
||||
if (model.rowHeight > 0) {
|
||||
// 预计算并缓存高度,避免使用 UITableViewAutomaticDimension
|
||||
if (model.rowHeight <= 0) {
|
||||
[self calculateRowHeightForModel:model];
|
||||
}
|
||||
|
||||
return model.rowHeight + 20;
|
||||
}
|
||||
|
||||
// 否则,使用自适应高度
|
||||
// return 100;
|
||||
return UITableViewAutomaticDimension;
|
||||
// 新增方法:预计算行高
|
||||
- (void)calculateRowHeightForModel:(XPMessageInfoModel *)model {
|
||||
if (!model || !model.content) {
|
||||
model.rowHeight = 44; // 默认高度
|
||||
return;
|
||||
}
|
||||
|
||||
// 使用 YYTextLayout 计算文本高度
|
||||
YYTextContainer *container = [YYTextContainer new];
|
||||
container.size = CGSizeMake(kRoomMessageMaxWidth - 24, MAXFLOAT);
|
||||
container.maximumNumberOfRows = 0;
|
||||
|
||||
YYTextLayout *layout = [YYTextLayout layoutWithContainer:container text:model.content];
|
||||
model.rowHeight = layout.textBoundingSize.height;
|
||||
|
||||
// 确保最小高度
|
||||
if (model.rowHeight < 44) {
|
||||
model.rowHeight = 44;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||
@@ -1492,8 +1539,8 @@ NSString * const kRoomShowTopicKey = @"kRoomShowTopicKey";
|
||||
_messageTableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
|
||||
_messageTableView.delegate = self;
|
||||
_messageTableView.dataSource = self;
|
||||
_messageTableView.rowHeight = UITableViewAutomaticDimension;
|
||||
// _messageTableView.estimatedRowHeight = 44; // 预估高度
|
||||
// 移除 UITableViewAutomaticDimension,使用预计算的高度
|
||||
_messageTableView.rowHeight = 64; // 设置一个合理的默认高度
|
||||
_messageTableView.tableFooterView = [UIView new];
|
||||
_messageTableView.separatorStyle = UITableViewCellSeparatorStyleNone;
|
||||
_messageTableView.backgroundColor = [UIColor clearColor];
|
||||
|
Reference in New Issue
Block a user