diff --git a/YuMi/Modules/YMRoom/View/MessageContainerView/View/XPRoomMessageTableViewCell.m b/YuMi/Modules/YMRoom/View/MessageContainerView/View/XPRoomMessageTableViewCell.m index cf82b38f..da59ed97 100644 --- a/YuMi/Modules/YMRoom/View/MessageContainerView/View/XPRoomMessageTableViewCell.m +++ b/YuMi/Modules/YMRoom/View/MessageContainerView/View/XPRoomMessageTableViewCell.m @@ -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)); }]; } diff --git a/YuMi/Modules/YMRoom/View/MessageContainerView/XPRoomMessageContainerView.m b/YuMi/Modules/YMRoom/View/MessageContainerView/XPRoomMessageContainerView.m index 7581bac5..d6763b27 100644 --- a/YuMi/Modules/YMRoom/View/MessageContainerView/XPRoomMessageContainerView.m +++ b/YuMi/Modules/YMRoom/View/MessageContainerView/XPRoomMessageContainerView.m @@ -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]; - [self.messageTableView reloadData]; + + // 如果有删除操作,使用 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]; - [self.messageTableView reloadData]; + + // 如果有删除操作,使用 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) { - return model.rowHeight + 20; + // 预计算并缓存高度,避免使用 UITableViewAutomaticDimension + if (model.rowHeight <= 0) { + [self calculateRowHeightForModel:model]; } - // 否则,使用自适应高度 -// return 100; - return UITableViewAutomaticDimension; + return model.rowHeight + 20; +} + +// 新增方法:预计算行高 +- (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];