diff --git a/YuMi.xcodeproj/project.pbxproj b/YuMi.xcodeproj/project.pbxproj index df6077c7..67a81777 100644 --- a/YuMi.xcodeproj/project.pbxproj +++ b/YuMi.xcodeproj/project.pbxproj @@ -496,6 +496,7 @@ 23FF42762AA6E1480055733C /* XPHomeRecommendOtherRoomView.m in Sources */ = {isa = PBXBuildFile; fileRef = 23FF42752AA6E1480055733C /* XPHomeRecommendOtherRoomView.m */; }; 23FF42792AA6E19C0055733C /* HomeMenuSourceModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 23FF42782AA6E19C0055733C /* HomeMenuSourceModel.m */; }; 23FF428E2AAB2D3A0055733C /* XPCandyTreeBuyView.m in Sources */ = {isa = PBXBuildFile; fileRef = 23FF428D2AAB2D3A0055733C /* XPCandyTreeBuyView.m */; }; + 4C1892992CF84349004D4426 /* RoomCahtCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C1892982CF84349004D4426 /* RoomCahtCell.m */; }; 4C6E1F752CEAEC3C0073D0A3 /* ShoppingMallTagView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C6E1F742CEAEC3C0073D0A3 /* ShoppingMallTagView.m */; }; 4C6E1F792CEB12780073D0A3 /* UIView+GradientLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C6E1F782CEB12780073D0A3 /* UIView+GradientLayer.m */; }; 4C6E1F7C2CEB25B10073D0A3 /* ShoppingMallItemPreview.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C6E1F7B2CEB25B10073D0A3 /* ShoppingMallItemPreview.m */; }; @@ -2578,6 +2579,8 @@ 23FF42782AA6E19C0055733C /* HomeMenuSourceModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HomeMenuSourceModel.m; sourceTree = ""; }; 23FF428C2AAB2D3A0055733C /* XPCandyTreeBuyView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = XPCandyTreeBuyView.h; sourceTree = ""; }; 23FF428D2AAB2D3A0055733C /* XPCandyTreeBuyView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = XPCandyTreeBuyView.m; sourceTree = ""; }; + 4C1892972CF84349004D4426 /* RoomCahtCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RoomCahtCell.h; sourceTree = ""; }; + 4C1892982CF84349004D4426 /* RoomCahtCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RoomCahtCell.m; sourceTree = ""; }; 4C6E1F732CEAEC3C0073D0A3 /* ShoppingMallTagView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ShoppingMallTagView.h; sourceTree = ""; }; 4C6E1F742CEAEC3C0073D0A3 /* ShoppingMallTagView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ShoppingMallTagView.m; sourceTree = ""; }; 4C6E1F772CEB12780073D0A3 /* UIView+GradientLayer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UIView+GradientLayer.h"; sourceTree = ""; }; @@ -8670,6 +8673,8 @@ E84B0E412727EE0A008818C6 /* XPRoomMessageHeaderView.m */, E84B0E3D2727EDF6008818C6 /* XPRoomMessageTableViewCell.h */, E84B0E3E2727EDF6008818C6 /* XPRoomMessageTableViewCell.m */, + 4C1892972CF84349004D4426 /* RoomCahtCell.h */, + 4C1892982CF84349004D4426 /* RoomCahtCell.m */, ); path = View; sourceTree = ""; @@ -11910,6 +11915,7 @@ 23194DCD2AD14BF000649F51 /* DDASLLogger.m in Sources */, E85E7B492A4EB0D300B6D00A /* XPMineGuildSearchViewController.m in Sources */, 238A900A2BA9756600828123 /* PIUniversalBannerModel.m in Sources */, + 4C1892992CF84349004D4426 /* RoomCahtCell.m in Sources */, E85E7B012A4EB0D200B6D00A /* XPSuperAdminSetPresenter.m in Sources */, 18F404B7276095D700A6C548 /* SessionChatLimitView.m in Sources */, E8788942273A55AD00BF1D57 /* XPGiftUsersView.m in Sources */, diff --git a/YuMi/Modules/YMMessage/View/Session/Content/MessageContentTextClickable.m b/YuMi/Modules/YMMessage/View/Session/Content/MessageContentTextClickable.m index 7d4e0fe3..3dcc749c 100644 --- a/YuMi/Modules/YMMessage/View/Session/Content/MessageContentTextClickable.m +++ b/YuMi/Modules/YMMessage/View/Session/Content/MessageContentTextClickable.m @@ -227,7 +227,7 @@ break; case SecretaryRouterType_My_Dressup: { - ShoppingMallViewController * dressUpVC = [[ShoppingMallViewController alloc] init]; + MyDressingViewController * dressUpVC = [[MyDressingViewController alloc] init]; // dressUpVC.currentIndex = [value integerValue]; [[XCCurrentVCStackManager shareManager].getCurrentVC.navigationController pushViewController:dressUpVC animated:YES]; } diff --git a/YuMi/Modules/YMMessage/View/Session/SessionViewController.m b/YuMi/Modules/YMMessage/View/Session/SessionViewController.m index 2ce55b67..f3c701bd 100644 --- a/YuMi/Modules/YMMessage/View/Session/SessionViewController.m +++ b/YuMi/Modules/YMMessage/View/Session/SessionViewController.m @@ -80,6 +80,7 @@ #import "Api+Message.h" #import "MessageGameOrderModel.h" #import "VIPCenterViewController.h" +#import "XPSkillCardPlayerManager.h" @interface CheckLimitModel :PIBaseModel @property (nonatomic, assign) BOOL chat; @@ -149,6 +150,7 @@ [self initHeaderAndFooterRrfresh]; [[NIMSDK sharedSDK].chatManager addDelegate:self]; [[NIMSDK sharedSDK].conversationManager addDelegate:self]; + [self.presenter getUserInfoWithUid:[AccountInfoStorage instance].getUid]; } - (void)viewWillAppear:(BOOL)animated { @@ -511,8 +513,12 @@ } - (void)onGetUserInfoSuccess:(UserInfoModel *)userInfo { - self.userInfo = userInfo; - [self.sessionTableView reloadData]; + if (userInfo.uid == [AccountInfoStorage instance].getUid.integerValue) { + [XPSkillCardPlayerManager shareInstance].userInfoModel = userInfo; + } else { + self.userInfo = userInfo; + [self.sessionTableView reloadData]; + } } #pragma mark - MessageCellDelegate diff --git a/YuMi/Modules/YMRoom/View/MessageContainerView/Model/XPMessageInfoModel.h b/YuMi/Modules/YMRoom/View/MessageContainerView/Model/XPMessageInfoModel.h index fc278c97..188ee697 100644 --- a/YuMi/Modules/YMRoom/View/MessageContainerView/Model/XPMessageInfoModel.h +++ b/YuMi/Modules/YMRoom/View/MessageContainerView/Model/XPMessageInfoModel.h @@ -10,7 +10,7 @@ NS_ASSUME_NONNULL_BEGIN @interface XPMessageInfoModel : PIBaseModel -@property(nonatomic,assign) BOOL isChatHall; + @property(nonatomic,assign) BOOL isBoom; @property(nonatomic,strong) PIRoomPhotoAlbumItemModel *albumModel; @property(nonatomic,copy) NSString *vipIcon; diff --git a/YuMi/Modules/YMRoom/View/MessageContainerView/Model/XPMessageInfoModel.m b/YuMi/Modules/YMRoom/View/MessageContainerView/Model/XPMessageInfoModel.m index df078949..f0ba47e0 100644 --- a/YuMi/Modules/YMRoom/View/MessageContainerView/Model/XPMessageInfoModel.m +++ b/YuMi/Modules/YMRoom/View/MessageContainerView/Model/XPMessageInfoModel.m @@ -26,10 +26,9 @@ } - (void)setContent:(NSAttributedString *)content { - _content = content; - self.rowHeight = [self heightForAttributedText:content maxWidth:kRoomMessageMaxWidth]; + _content = content; // CGFloat width = isMSRTL() ? 10 : 0; ////// width = self.vipIcon.length > 0 ? width + 15 : width; @@ -56,6 +55,17 @@ } - (CGFloat)heightForAttributedText:(NSAttributedString *)attributedText maxWidth:(CGFloat)maxWidth { + + CGSize containerSize = CGSizeMake(maxWidth, CGFLOAT_MAX); + YYTextContainer *_container = [YYTextContainer containerWithSize:containerSize]; + _container.maximumNumberOfRows = 0; // 不限制行数 + YYTextLayout *_layout = [YYTextLayout layoutWithContainer:_container text:attributedText]; + CGFloat textHeight = _layout.textBoundingSize.height; + return textHeight + self.contentTopMargin + self.contentBottomMargin + self.cellBottomMargin; + +// return [attributedText.string boundingRectWithSize:CGSizeMake(maxWidth, CGFLOAT_MAX) options:NSStringDrawingTruncatesLastVisibleLine | NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:kRoomMessageDefalutFont]} context:nil].size.height; + + // 创建一个 YYTextContainer YYTextContainer *container = [YYTextContainer new]; container.size = CGSizeMake(maxWidth, CGFLOAT_MAX); // 设置宽度,支持无限高度 @@ -63,29 +73,45 @@ // 遍历富文本,设置未加载图片的占位尺寸 // 确认是否 “@用户名” 会影响计算结果 - NSInteger index = 0; - NSMutableAttributedString *mutableAttributedText = [attributedText mutableCopy]; - [mutableAttributedText enumerateAttribute:YYTextAttachmentAttributeName - inRange:NSMakeRange(0, mutableAttributedText.length) - options:0 - usingBlock:^(id value, NSRange range, BOOL *stop) { - - if ([value isKindOfClass:[YYTextAttachment class]]) { - // TODO: 把图片变为字符串来占位, 观察结果是第二行字符长度少于前缀图片,则会高度减少 - YYTextAttachment *attachment = (YYTextAttachment *)value; - NSLog(@" ---00--- : %@", attachment.content); - if (attachment.content == nil) { - attachment.content = [[UIView alloc] init]; // 占位内容 - NSValue *v = [self.extraSizeArray xpSafeObjectAtIndex:index]; - if (value) { - UIView *placeholderView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, [v CGSizeValue].width, [v CGSizeValue].height)]; - attachment.content = placeholderView; // 使用占位尺寸 - } else { - *stop = YES; + NSMutableAttributedString *mutableAttributedText = [[NSMutableAttributedString alloc] initWithAttributedString:attributedText.copy]; + if (isMSRTL()) { + NSInteger index = 0; + [mutableAttributedText enumerateAttribute:YYTextAttachmentAttributeName + inRange:NSMakeRange(0, mutableAttributedText.length) + options:0 + usingBlock:^(id value, NSRange range, BOOL *stop) { + + if ([value isKindOfClass:[YYTextAttachment class]]) { + // TODO: 把图片变为字符串来占位, 观察结果是第二行字符长度少于前缀图片,则会高度减少 + YYTextAttachment *attachment = (YYTextAttachment *)value; + // NSLog(@" ---00--- : %@", attachment.content); + + if (attachment.content && [attachment.content isKindOfClass:[NetImageView class]]) { + NSValue *v = [self.extraSizeArray xpSafeObjectAtIndex:index]; + NSString *tempString = @""; + if (value) { + CGSize size = [v CGSizeValue]; + // UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, size.width, size.height)]; + // attachment.content = view; + if (size.width <= 20) { + tempString = @"ABCD"; + } else if (size.width <=40) { + tempString = @"ABCDEF"; + } else { + tempString = @"ABCDEFGH"; + } + } + + NSAttributedString *replaceString = [[NSAttributedString alloc] initWithString:tempString + attributes:@{ + NSFontAttributeName: kFontRegular(kRoomMessageDefalutFont), + NSForegroundColorAttributeName: [UIColor whiteColor] + }]; + [mutableAttributedText replaceCharactersInRange:range withAttributedString:replaceString]; } } - } - }]; + }]; + } // 通过 YYTextLayout 创建布局 YYTextLayout *layout = [YYTextLayout layoutWithContainer:container text:mutableAttributedText]; diff --git a/YuMi/Modules/YMRoom/View/MessageContainerView/MsRoomMessageMainView.m b/YuMi/Modules/YMRoom/View/MessageContainerView/MsRoomMessageMainView.m index 8d249f97..66913280 100644 --- a/YuMi/Modules/YMRoom/View/MessageContainerView/MsRoomMessageMainView.m +++ b/YuMi/Modules/YMRoom/View/MessageContainerView/MsRoomMessageMainView.m @@ -37,6 +37,7 @@ self = [super init]; if (self) { self.hostDelegate = delegate; + self.hidden = YES; [self installUI]; [self installConstraints]; @@ -142,10 +143,12 @@ - (void)onRoomMiniEntered { + self.hidden = NO; [self.messageListView onRoomMiniEntered]; } - (void)onRoomEntered { + self.hidden = NO; [self.messageListView onRoomEntered]; } diff --git a/YuMi/Modules/YMRoom/View/MessageContainerView/Tool/XPRoomMessageParser.m b/YuMi/Modules/YMRoom/View/MessageContainerView/Tool/XPRoomMessageParser.m index af8126c6..d05f1d58 100644 --- a/YuMi/Modules/YMRoom/View/MessageContainerView/Tool/XPRoomMessageParser.m +++ b/YuMi/Modules/YMRoom/View/MessageContainerView/Tool/XPRoomMessageParser.m @@ -59,29 +59,6 @@ @implementation XPRoomMessageParser -- (XPMessageInfoModel*)parseMessageAttributeForChatHall:(NIMMessage *)message{ - NIMMessageType messageType = message.messageType; - XPMessageInfoModel * messageInfo = [[XPMessageInfoModel alloc] init]; - messageInfo.isChatHall = YES; - switch (messageType) { - case NIMMessageTypeText: - { - XPMessageInfoModel *model = [self makeChatAttribute:message messageInfo:messageInfo]; - return model != nil ? model : [XPMessageInfoModel new]; - break; - } - - case NIMMessageTypeCustom: - { - XPMessageInfoModel *model = [self makeCustomAttribute:message messageInfo:messageInfo]; - return model != nil ? model : [XPMessageInfoModel new]; - break; - } - default: - return [XPMessageInfoModel new]; - } -} - - (XPMessageInfoModel*)parseBroadcastMessageAttribute:(NIMBroadcastMessage *)message { if (message.content) { NSDictionary *msgDictionary = [message.content toJSONObject]; @@ -266,7 +243,7 @@ getNick = model.nick; } - NSString * nick = [NSString stringWithFormat:@"%@:", getNick]; + NSString *nick = [NSString stringWithFormat:@"%@:", getNick]; if ([message.from isEqualToString:uid]) { nick = YMLocalizedString(@"XPRoomMessageParser0"); } @@ -274,7 +251,10 @@ NSMutableAttributedString * attribute = [[NSMutableAttributedString alloc] init]; ///官方新用户 - [attribute appendAttributedString:[self createOfficalAndNewuserAttribute:model.defUser newUser:model.newUser fromSayHelloChannel:model.fromSayHelloChannel]]; + if (model.defUser == UserLevelType_Offical || model.newUser) { + [attribute appendAttributedString:[self createOfficalAndNewuserAttribute:model.defUser newUser:model.newUser fromSayHelloChannel:model.fromSayHelloChannel]]; + } + if ([self isCurrentRoomSuperAdmin:message.from]) { [attribute appendAttributedString:[self createLanguageImageAttribute:@"common_super_admin"]]; } @@ -299,13 +279,15 @@ [attribute appendAttributedString:[self createSapceAttribute:2]]; } }else{ - if (model.inRoomNameplatePic.length > 0 && model.inRoomNameplateWord.length > 0) { //铭牌有图片加文字 +// if (model.inRoomNameplatePic.length > 0 && model.inRoomNameplateWord.length > 0) { //铭牌有图片加文字 + if (model.inRoomNameplatePic.length > 0) { [attribute appendAttributedString:[self createNameplateAttibute:model.inRoomNameplateWord image:model.inRoomNameplatePic textFont:[UIFont systemFontOfSize:9]]]; [attribute appendAttributedString:[self createSapceAttribute:2]]; - } else if (model.inRoomNameplatePic.length > 0) {//铭牌只有图片 - [attribute appendAttributedString:[self createUrlImageAttribute:model.inRoomNameplatePic]]; - [attribute appendAttributedString:[self createSapceAttribute:2]]; } +// } else if (model.inRoomNameplatePic.length > 0) {//铭牌只有图片 +// [attribute appendAttributedString:[self createUrlImageAttribute:model.inRoomNameplatePic]]; +// [attribute appendAttributedString:[self createSapceAttribute:2]]; +// } } [attribute appendAttributedString:[self createTextAttribute:nick color:[DJDKMIMOMColor messageDefaultTextColor] font:kRoomMessageDefalutFont]]; [attribute appendAttributedString:[self createSapceAttribute:2]]; @@ -313,30 +295,26 @@ id nickNameNifo = message.remoteExt[@"atNames"]; NSMutableAttributedString *msgStr; if (message.text) { - if(messageInfo.isChatHall == YES){ - QEmotionHelper *faceManager = [QEmotionHelper sharedEmotionHelper]; - msgStr = [faceManager attributedStringByText:message.text font:[UIFont systemFontOfSize:kRoomMessageDefalutFont]]; - [msgStr addAttributes:@{NSForegroundColorAttributeName: [DJDKMIMOMColor messageTextColor]} range:[msgStr.string rangeOfString:msgStr.string]]; - - }else{ - msgStr = [[NSMutableAttributedString alloc] initWithString:message.text]; - [msgStr addAttribute:NSForegroundColorAttributeName - value:[DJDKMIMOMColor messageTextColor] - range:NSMakeRange(0, msgStr.length)]; - if ([nickNameNifo isKindOfClass:[NSArray class]]) { - for (NSString *nick in nickNameNifo) { - NSRange range = [message.text rangeOfString:nick]; - if (range.length) { - [msgStr yy_setTextHighlightRange:range color:UIColorFromRGB(0xFD85C9) backgroundColor:[UIColor clearColor] userInfo:nil]; - } + msgStr = [[NSMutableAttributedString alloc] initWithString:message.text + attributes:@{ + NSFontAttributeName: kFontRegular(kRoomMessageDefalutFont) + }]; + [msgStr addAttribute:NSForegroundColorAttributeName + value:[DJDKMIMOMColor messageTextColor] + range:NSMakeRange(0, msgStr.length)]; + if ([nickNameNifo isKindOfClass:[NSArray class]]) { + for (NSString *nick in nickNameNifo) { + NSRange range = [message.text rangeOfString:nick]; + if (range.length) { + [msgStr yy_setTextHighlightRange:range color:UIColorFromRGB(0xFD85C9) backgroundColor:[UIColor clearColor] userInfo:nil]; } } } [attribute appendAttributedString:msgStr]; } - if(messageInfo.isChatHall == NO){ - [self attributeAddLongPressHihtLight:attribute uid:message.from nick:((NIMMessageChatroomExtension *)message.messageExt).roomNickname]; - } + [self attributeAddLongPressHihtLight:attribute + uid:message.from + nick:((NIMMessageChatroomExtension *)message.messageExt).roomNickname]; messageInfo.content = attribute; messageInfo.vipIcon = model.vipIcon; @@ -382,6 +360,9 @@ case NIMChatroomEventTypeEnter:///进入房间 { NSString* nick = member.nick.length > 0 ? member.nick : @""; + if ([nick isEqualToString:@"Platform New User"]) { + nick = @""; + } NSMutableAttributedString * attribute = [[NSMutableAttributedString alloc] init]; NSDictionary * dic = [(NSDictionary *)messageExt.roomExt.toJSONObject objectForKey:message.from]; XPMessageRemoteExtModel * extModel = [XPMessageRemoteExtModel modelWithDictionary:dic]; @@ -571,7 +552,12 @@ } }else if ([model.type isEqualToString:@"IMAGE"]){ - NSMutableAttributedString *attImage = [self createUrlImageAttribute:model.image size:CGSizeMake(model.width, model.height)]; + if (!messageInfo.extraSizeArray) { + messageInfo.extraSizeArray = @[].mutableCopy; + } + CGSize placeHolderSize = CGSizeMake(model.width, model.height); + [messageInfo.extraSizeArray addObject:[NSValue valueWithCGSize:placeHolderSize]]; + NSMutableAttributedString *attImage = [self createUrlImageAttribute:model.image size:placeHolderSize]; [attImage appendAttributedString:[self createSapceAttribute:2]]; if ([attribute.string containsString:[NSString stringWithFormat:@"{%@}",model.key]]){ [attribute replaceCharactersInRange:[attribute.string rangeOfString:[NSString stringWithFormat:@"{%@}",model.key]] withAttributedString:attImage]; @@ -1413,18 +1399,21 @@ } imageView.contentMode = UIViewContentModeScaleAspectFit; // 铭牌文字 - UILabel *label = [[UILabel alloc] init]; - label.textAlignment = NSTextAlignmentCenter; - label.font = [UIFont boldSystemFontOfSize:12]; - label.adjustsFontSizeToFitWidth = YES; - label.textColor = UIColor.whiteColor; - label.text = tagName; - [imageView addSubview:label]; - [label mas_makeConstraints:^(MASConstraintMaker *make) { - make.leading.mas_equalTo(27); - make.trailing.mas_equalTo(-8); - make.centerY.mas_equalTo(0); - }]; + if ([NSString isEmpty:tagName]) { + UILabel *label = [[UILabel alloc] init]; + label.textAlignment = NSTextAlignmentCenter; + label.font = [UIFont boldSystemFontOfSize:12]; + label.adjustsFontSizeToFitWidth = YES; + label.textColor = UIColor.whiteColor; + label.text = tagName; + [imageView addSubview:label]; + [label mas_makeConstraints:^(MASConstraintMaker *make) { + make.leading.mas_equalTo(27); + make.trailing.mas_equalTo(-8); + make.centerY.mas_equalTo(0); + }]; + } + NSMutableAttributedString *string = [NSMutableAttributedString yy_attachmentStringWithContent:imageView contentMode:UIViewContentModeScaleAspectFit attachmentSize:imageView.bounds.size alignToFont:[UIFont boldSystemFontOfSize:12] alignment:YYTextVerticalAlignmentCenter]; return string; } @@ -1446,7 +1435,7 @@ } imageView.layer.masksToBounds = YES; imageView.contentMode = UIViewContentModeScaleAspectFit; - NSMutableAttributedString * attrString = [NSMutableAttributedString yy_attachmentStringWithContent:imageView contentMode:UIViewContentModeScaleAspectFit attachmentSize:CGSizeMake(imageView.bounds.size.width, imageView.bounds.size.height) alignToFont:[UIFont systemFontOfSize:15.0] alignment:YYTextVerticalAlignmentCenter]; + NSMutableAttributedString * attrString = [NSMutableAttributedString yy_attachmentStringWithContent:imageView contentMode:UIViewContentModeScaleAspectFit attachmentSize:CGSizeMake(imageView.bounds.size.width, imageView.bounds.size.height) alignToFont:kFontRegular(kRoomMessageDefalutFont) alignment:YYTextVerticalAlignmentCenter]; return attrString; } /// 生成一个图片的富文本 @@ -1460,7 +1449,7 @@ imageView.bounds = CGRectMake(0, 0, size.width, size.height); imageView.layer.masksToBounds = YES; imageView.contentMode = UIViewContentModeScaleAspectFit; - NSMutableAttributedString * attrString = [NSMutableAttributedString yy_attachmentStringWithContent:imageView contentMode:UIViewContentModeScaleAspectFit attachmentSize:CGSizeMake(imageView.bounds.size.width, imageView.bounds.size.height) alignToFont:[UIFont systemFontOfSize:15.0] alignment:YYTextVerticalAlignmentCenter]; + NSMutableAttributedString * attrString = [NSMutableAttributedString yy_attachmentStringWithContent:imageView contentMode:UIViewContentModeScaleAspectFit attachmentSize:CGSizeMake(imageView.bounds.size.width, imageView.bounds.size.height) alignToFont:kFontRegular(kRoomMessageDefalutFont) alignment:YYTextVerticalAlignmentCenter]; return attrString; } @@ -1523,8 +1512,8 @@ NSMutableParagraphStyle *paraStyle = [[NSMutableParagraphStyle alloc] init]; paraStyle.lineSpacing = 4.0f;//行间距 // 强制排版(从左到右) - paraStyle.alignment = NSTextAlignmentLeft; - paraStyle.baseWritingDirection = NSWritingDirectionLeftToRight; + paraStyle.alignment = isMSRTL() ? NSTextAlignmentRight : NSTextAlignmentLeft; + paraStyle.baseWritingDirection = isMSRTL() ? NSWritingDirectionRightToLeft : NSWritingDirectionLeftToRight; return paraStyle; } diff --git a/YuMi/Modules/YMRoom/View/MessageContainerView/View/RoomCahtCell.h b/YuMi/Modules/YMRoom/View/MessageContainerView/View/RoomCahtCell.h new file mode 100644 index 00000000..d92bd393 --- /dev/null +++ b/YuMi/Modules/YMRoom/View/MessageContainerView/View/RoomCahtCell.h @@ -0,0 +1,23 @@ +// +// RoomCahtCell.h +// YuMi +// +// Created by P on 2024/11/28. +// + +#import + +#import "XPMessageInfoModel.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface RoomCahtCell : UITableViewCell + ++ (void)registerTo:(UITableView *)tableView; ++ (RoomCahtCell *)cellFor:(UITableView *)tableView; + +@property (nonatomic,strong) XPMessageInfoModel *messageInfo; + +@end + +NS_ASSUME_NONNULL_END diff --git a/YuMi/Modules/YMRoom/View/MessageContainerView/View/RoomCahtCell.m b/YuMi/Modules/YMRoom/View/MessageContainerView/View/RoomCahtCell.m new file mode 100644 index 00000000..1ad51e50 --- /dev/null +++ b/YuMi/Modules/YMRoom/View/MessageContainerView/View/RoomCahtCell.m @@ -0,0 +1,180 @@ +// +// MessageCell.m +// YuMi +// +// Created by P on 2024/11/28. +// + +#import "RoomCahtCell.h" + +#import "NetImageView.h" +#import "XPNetImageYYLabel.h" +#import "XPRoomMessageConstant.h" + +static NSString *MessageCellID = @"MessageCell"; + +@interface RoomCahtCell () + +@property (nonatomic,strong) NetImageView *bubbleImageView; +@property (nonatomic,strong) XPNetImageYYLabel *contentLabel; + +@end + +@implementation RoomCahtCell + ++ (void)registerTo:(UITableView *)tableView { + [tableView registerClass:[self class] forCellReuseIdentifier:MessageCellID]; +} + ++ (RoomCahtCell *)cellFor:(UITableView *)tableView { + return [tableView dequeueReusableCellWithIdentifier:MessageCellID]; +} + +- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; + if (self) { + self.selectionStyle = UITableViewCellSelectionStyleNone; + self.backgroundColor = [UIColor clearColor]; + + [self setupViews]; + [self setupConstraints]; + } + return self; +} + +//TODO: +//修改 messageInfo 的组装流程,获取到消息后,先放入处理队列-1。 +// 队列-1 会按顺序处理消息,并预下载图片,所有图片下载完成后,用 cache 图片生成富文本,并放入队列-2 +// 队列-2 会按顺序计算富文本的 size,并插入到需要显示的消息队列中,并将 size 传递到外部 + +#pragma mark - 配置数据 +- (void)setMessageInfo:(XPMessageInfoModel *)messageInfo { + _messageInfo = messageInfo; + if (messageInfo) { + + if ([NSString isEmpty:messageInfo.bubbleImageUrl]) { + self.bubbleImageView.hidden = NO; + self.bubbleImageView.image = [UIImage imageWithColor:[UIColor colorWithWhite:0 alpha:0.3]]; + } else { + @kWeakify(self); + [self.bubbleImageView loadImageWithUrl:messageInfo.bubbleImageUrl + completion:^(UIImage * _Nullable image, NSURL * _Nonnull url) { + @kStrongify(self); + UIImage *image1 = [UIImage imageWithCGImage:image.CGImage scale:2.0 orientation:UIImageOrientationUp]; + UIImage *cutImage = [image1 cropRightAndBottomPixels:2]; + self.bubbleImageView.image = [self resizableImage:cutImage]; + }]; + self.bubbleImageView.hidden = messageInfo.isHiddenBubble; + } + + NSMutableAttributedString *s = [[NSMutableAttributedString alloc] initWithAttributedString:messageInfo.content]; +// if (isMSRTL()) { +// s.yy_writingDirection = @[@(kCTWritingDirectionRightToLeft)]; +// } + + self.contentLabel.attributedText = messageInfo.content; + + // 更新 contentLabel 高度 + [self.contentLabel layoutIfNeeded]; + CGSize labelSize = [self.contentLabel systemLayoutSizeFittingSize:UILayoutFittingCompressedSize]; + [self.contentLabel mas_updateConstraints:^(MASConstraintMaker *make) { + make.height.mas_equalTo(labelSize.height); + }]; + + // 更新气泡背景约束 + [self.bubbleImageView layoutIfNeeded]; + [self.bubbleImageView mas_updateConstraints:^(MASConstraintMaker *make) { + make.edges.equalTo(self.contentLabel).insets(UIEdgeInsetsMake(-8, -8, -8, -8)); + }]; + } +} + +#pragma mark - 设置视图 + +- (void)setupViews { + // 背景图片 + self.bubbleImageView = [[NetImageView alloc] init]; + self.bubbleImageView.contentMode = UIViewContentModeScaleAspectFill; + self.bubbleImageView.clipsToBounds = YES; + [self.contentView addSubview:self.bubbleImageView]; + + // 消息标签 + self.contentLabel = [[XPNetImageYYLabel alloc] init]; + self.contentLabel.numberOfLines = 0; + self.contentLabel.preferredMaxLayoutWidth = kRoomMessageMaxWidth - 24;//UIScreen.mainScreen.bounds.size.width * (3.0 / 2.0); + [self.contentView addSubview:self.contentLabel]; + [self.bubbleImageView setCornerRadius:8]; +} + +#pragma mark - 设置约束 + +- (void)setupConstraints { + // 消息标签约束 + [self.contentLabel mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.equalTo(self.contentView).offset(16); + make.bottom.equalTo(self.contentView).offset(-16); + if (isMSRTL()) { + make.leading.equalTo(self.contentView).offset(12).priorityHigh(); + make.trailing.lessThanOrEqualTo(self.contentView).offset(-12); + } else { + make.leading.equalTo(self.contentView).offset(12); + make.trailing.lessThanOrEqualTo(self.contentView).offset(-12).priorityHigh(); + } + }]; + + // 背景图片约束 + [self.bubbleImageView mas_makeConstraints:^(MASConstraintMaker *make) { + make.edges.equalTo(self.contentLabel).insets(UIEdgeInsetsMake(-8, -8, -8, -8)); // 比 label 多 padding + }]; + + +// [self.contentLabel mas_makeConstraints:^(MASConstraintMaker *make) { +// if (isMSRTL()) { +// make.right.equalTo(self.contentView).offset(-8); // 右对齐 +// } else { +// make.left.equalTo(self.contentView).offset(8); // 左对齐 +// } +// make.top.equalTo(self.contentView).offset(8); // 距顶部8 +// make.bottom.equalTo(self.contentView).offset(-8); // 距底部8 +//// make.width.mas_lessThanOrEqualTo(kRoomMessageMaxWidth - 24); // 最大宽度 +// }]; +// +// [self.bubbleImageView mas_makeConstraints:^(MASConstraintMaker *make) { +// make.edges.equalTo(self.contentLabel); // 背景图片与标签尺寸一致 +// }]; + + +// // 背景图片的约束 +// [self.bubbleImageView mas_makeConstraints:^(MASConstraintMaker *make) { +// if (isMSRTL()) { +// make.right.equalTo(self.contentView).offset(-8); +// } else { +// make.left.equalTo(self.contentView).offset(8); +// } +// make.top.equalTo(self.contentView).offset(8); +// make.width.lessThanOrEqualTo(@(UIScreen.mainScreen.bounds.size.width * 3.0 / 2.0)); +// make.bottom.equalTo(self.contentView).offset(-8); +// make.edges.equalTo(self.contentView).insets(UIEdgeInsetsMake(8, 8, 8, 8)); +// }]; +// +// // 消息标签的约束 +// [self.contentLabel mas_makeConstraints:^(MASConstraintMaker *make) { +// make.left.equalTo(self.bubbleImageView.mas_left).offset(12); +// make.right.equalTo(self.bubbleImageView.mas_right).offset(-12); +// make.top.equalTo(self.bubbleImageView.mas_top).offset(16); +// make.bottom.equalTo(self.bubbleImageView.mas_bottom).offset(-16); +// }]; +} + +- (UIImage*)resizableImage:(UIImage *)image { + //图片拉伸区域 + CGSize size = image.size; + CGFloat top = size.height * 0.3; + CGFloat left = size.width * 0.3; + CGFloat right = size.width * 0.3; + CGFloat bottom = size.height * 0.3; + return [image resizableImageWithCapInsets:UIEdgeInsetsMake(top, left, bottom, right) + resizingMode:UIImageResizingModeStretch]; +} + +@end diff --git a/YuMi/Modules/YMRoom/View/MessageContainerView/View/XPNetImageYYLabel.m b/YuMi/Modules/YMRoom/View/MessageContainerView/View/XPNetImageYYLabel.m index 6f0097a4..769bb023 100644 --- a/YuMi/Modules/YMRoom/View/MessageContainerView/View/XPNetImageYYLabel.m +++ b/YuMi/Modules/YMRoom/View/MessageContainerView/View/XPNetImageYYLabel.m @@ -13,9 +13,33 @@ @implementation XPNetImageYYLabel - (void)setAttributedText:(NSAttributedString *)attributedText { + if (!attributedText) return; + NSMutableAttributedString* attributedTextCopy = [attributedText mutableCopy]; CGSize maxSize = CGSizeMake(kRoomMessageMaxWidth - 24, MAXFLOAT); - +// if (isMSRTL()) { +// attributedTextCopy.yy_writingDirection = @[@(kCTWritingDirectionRightToLeft)]; +// } +// YYTextLayout * layout = [YYTextLayout layoutWithContainerSize:maxSize text:attributedText]; +// for (int i = 0; i< layout.attachments.count; i++) { +// YYTextAttachment * attachment = [layout.attachments xpSafeObjectAtIndex:i]; +// if (!attachment || ![attachment.content isKindOfClass:[NetImageView class]]) continue; +// NetImageView* imageView = attachment.content; +// NSValue * value = [layout.attachmentRanges xpSafeObjectAtIndex:i]; +// NSRange range = value.rangeValue; +// if (!imageView.imageUrl) continue; +// +// if (imageView.state == NetImageStateLoaded) { +// attributedTextCopy = [self updateNetImageAttribute:imageView attributes:attributedTextCopy range:range]; +// continue; +// }else { +// [imageView loadImage:^(UIImage * _Nonnull image, NSURL * _Nonnull url) { +// imageView.image = image; +// [super setAttributedText:[self updateNetImageAttribute:imageView attributes:attributedTextCopy range:range]]; +// }]; +// } +// } + self.maxWidth = maxSize.width - 8; CGSize size = [attributedText boundingRectWithSize:maxSize @@ -25,52 +49,117 @@ YYTextContainer *container = [YYTextContainer containerWithSize:CGSizeMake(size.width, MAXFLOAT)]; container.truncationType = YYTextTruncationTypeEnd; -// YYTextLayout * layout = [YYTextLayout layoutWithContainerSize:maxSize text:attributedText]; - YYTextLayout * layout = [YYTextLayout layoutWithContainer:container text:attributedText]; + YYTextLayout * layout = [YYTextLayout layoutWithContainerSize:maxSize text:attributedTextCopy]; +// YYTextLayout * layout = [YYTextLayout layoutWithContainer:container text:attributedText]; - for (YYTextAttachment *attachment in layout.attachments) { - if (!attachment || ![attachment.content isKindOfClass:[NetImageView class]]) continue; - NSInteger index = [layout.attachments indexOfObject:attachment]; - NetImageView* imageView = attachment.content; - if (!imageView.imageUrl) continue; + for (NSUInteger i = 0; i < layout.attachments.count; i++) { + YYTextAttachment *attachment = [layout.attachments xpSafeObjectAtIndex:i]; + if (![attachment.content isKindOfClass:[NetImageView class]]) { + continue; + } + + NetImageView *imageView = (NetImageView *)attachment.content; + if (!imageView.imageUrl){ + continue; + } + + NSValue *value = [layout.attachmentRanges xpSafeObjectAtIndex:i]; + if (!value) { + continue; + } - NSValue * value = [layout.attachmentRanges xpSafeObjectAtIndex:index]; NSRange range = value.rangeValue; if (imageView.state == NetImageStateLoaded) { - attributedTextCopy = [self updateNetImageAttribute:imageView attributes:attributedTextCopy range:range]; - continue; - }else { + attributedTextCopy = [self updateNetImageAttribute:imageView + attributes:attributedTextCopy + range:range]; + } else { @kWeakify(self); [imageView loadImage:^(UIImage * _Nonnull image, NSURL * _Nonnull url) { @kStrongify(self); - imageView.image = image; - [super setAttributedText:[self updateNetImageAttribute:imageView attributes:attributedTextCopy range:range]]; + dispatch_async(dispatch_get_main_queue(), ^{ + [self updateImageAndRefresh:imageView + attributedText:attributedTextCopy + range:range]; + }); }]; } } - self.textWidth = layout.textBoundingRect.size.width; +// for (YYTextAttachment *attachment in layout.attachments) { +// if (!attachment || ![attachment.content isKindOfClass:[NetImageView class]]) continue; +// NSInteger index = [layout.attachments indexOfObject:attachment]; +// NetImageView* imageView = attachment.content; +// if (!imageView.imageUrl) continue; +// +// NSValue * value = [layout.attachmentRanges xpSafeObjectAtIndex:index]; +// NSRange range = value.rangeValue; +// +// if (imageView.state == NetImageStateLoaded) { +// attributedTextCopy = [self updateNetImageAttribute:imageView attributes:attributedTextCopy range:range]; +// continue; +// }else { +// @kWeakify(self); +// [imageView loadImage:^(UIImage * _Nonnull image, NSURL * _Nonnull url) { +// @kStrongify(self); +// imageView.image = image; +// [super setAttributedText:[self updateNetImageAttribute:imageView attributes:attributedTextCopy range:range]]; +// }]; +// } +// } + self.textWidth = layout.textBoundingRect.size.width; [super setAttributedText:attributedTextCopy]; } -- (NSMutableAttributedString*)updateNetImageAttribute:(NetImageView*)imageView attributes:(NSMutableAttributedString*)attributes range:(NSRange)range{ - - UIImage* image = imageView.image; - CGSize size; - if (image != nil){ - CGFloat scale = image.size.width / image.size.height; - // 目前是根据原高度(imageView.bounds.size.height)等比例缩放图片。 - size = CGSizeMake(imageView.bounds.size.height * scale, imageView.bounds.size.height); - imageView.bounds = CGRectMake(0, 0, size.width, size.height); - }else{ - size = CGSizeMake(16, 16); - imageView.bounds = CGRectMake(0, 0, 16, 16); +- (void)updateImageAndRefresh:(NetImageView *)imageView + attributedText:(NSMutableAttributedString *)attributedText + range:(NSRange)range { + if (!imageView || !attributedText) return; + imageView.image = imageView.image ?: [UIImage new]; + NSMutableAttributedString *updatedAttributes = [self updateNetImageAttribute:imageView attributes:attributedText range:range]; + [super setAttributedText:updatedAttributes]; +} + +- (NSMutableAttributedString*)updateNetImageAttribute:(NetImageView*)imageView + attributes:(NSMutableAttributedString*)attributes + range:(NSRange)range{ + if (!imageView || !attributes) { + return attributes; } - NSMutableAttributedString * replaceAttr = [NSMutableAttributedString yy_attachmentStringWithContent:imageView contentMode:UIViewContentModeScaleAspectFit attachmentSize:size alignToFont:[UIFont systemFontOfSize:15.0] alignment:YYTextVerticalAlignmentCenter]; - [attributes replaceCharactersInRange:range withAttributedString:replaceAttr]; + + UIImage *image = imageView.image; + CGSize size = CGSizeMake(16, 16); // Default size + if (image) { + CGFloat scale = image.size.width / image.size.height; + size = CGSizeMake(imageView.bounds.size.height * scale, imageView.bounds.size.height); + } + imageView.bounds = CGRectMake(0, 0, size.width, size.height); + + NSMutableAttributedString *replaceAttr = [NSMutableAttributedString yy_attachmentStringWithContent:imageView + contentMode:UIViewContentModeScaleAspectFit + attachmentSize:size + alignToFont:[UIFont systemFontOfSize:15.0] + alignment:YYTextVerticalAlignmentCenter]; + [attributes replaceCharactersInRange:range withAttributedString:replaceAttr]; return attributes; + + +// UIImage* image = imageView.image; +// CGSize size; +// if (image != nil){ +// CGFloat scale = image.size.width / image.size.height; +// // 目前是根据原高度(imageView.bounds.size.height)等比例缩放图片。 +// size = CGSizeMake(imageView.bounds.size.height * scale, imageView.bounds.size.height); +// imageView.bounds = CGRectMake(0, 0, size.width, size.height); +// }else{ +// size = CGSizeMake(16, 16); +// imageView.bounds = CGRectMake(0, 0, 16, 16); +// } +// NSMutableAttributedString * replaceAttr = [NSMutableAttributedString yy_attachmentStringWithContent:imageView contentMode:UIViewContentModeScaleAspectFit attachmentSize:size alignToFont:[UIFont systemFontOfSize:15.0] alignment:YYTextVerticalAlignmentCenter]; +// [attributes replaceCharactersInRange:range withAttributedString:replaceAttr]; +// return attributes; } @end diff --git a/YuMi/Modules/YMRoom/View/MessageContainerView/View/XPRoomMessageHeaderView.m b/YuMi/Modules/YMRoom/View/MessageContainerView/View/XPRoomMessageHeaderView.m index 4a4d7fe9..a1d9e096 100644 --- a/YuMi/Modules/YMRoom/View/MessageContainerView/View/XPRoomMessageHeaderView.m +++ b/YuMi/Modules/YMRoom/View/MessageContainerView/View/XPRoomMessageHeaderView.m @@ -65,18 +65,18 @@ make.leading.trailing.mas_equalTo(self).inset(15); make.centerY.mas_equalTo(self.bubbleView); }]; - return; + } else { + [self.bubbleView mas_makeConstraints:^(MASConstraintMaker *make) { + make.leading.top.mas_equalTo(self); + make.width.mas_equalTo(kRoomMessageMaxWidth-10); + make.bottom.mas_equalTo(self).offset(-10); + }]; + + [self.titleLabel mas_makeConstraints:^(MASConstraintMaker *make) { + make.leading.trailing.mas_equalTo(self).inset(10); + make.centerY.mas_equalTo(self.bubbleView); + }]; } - [self.bubbleView mas_makeConstraints:^(MASConstraintMaker *make) { - make.leading.top.mas_equalTo(self); - make.width.mas_equalTo(kRoomMessageMaxWidth-10); - make.bottom.mas_equalTo(self).offset(-10); - }]; - - [self.titleLabel mas_makeConstraints:^(MASConstraintMaker *make) { - make.leading.trailing.mas_equalTo(self).inset(10); - make.centerY.mas_equalTo(self.bubbleView); - }]; } ///获取头部的高度 diff --git a/YuMi/Modules/YMRoom/View/MessageContainerView/View/XPRoomMessageTableViewCell.h b/YuMi/Modules/YMRoom/View/MessageContainerView/View/XPRoomMessageTableViewCell.h index 5450f211..ee9ae6cd 100644 --- a/YuMi/Modules/YMRoom/View/MessageContainerView/View/XPRoomMessageTableViewCell.h +++ b/YuMi/Modules/YMRoom/View/MessageContainerView/View/XPRoomMessageTableViewCell.h @@ -20,7 +20,7 @@ NS_ASSUME_NONNULL_BEGIN @interface XPRoomMessageTableViewCell : UITableViewCell -@property (nonatomic, assign) BOOL isLeftBigImage; +@property (nonatomic, assign) BOOL isLeftBoomImage; ///当前房间的类型 @property (nonatomic,assign) RoomType roomType; diff --git a/YuMi/Modules/YMRoom/View/MessageContainerView/View/XPRoomMessageTableViewCell.m b/YuMi/Modules/YMRoom/View/MessageContainerView/View/XPRoomMessageTableViewCell.m index 9e3821ab..962e67aa 100644 --- a/YuMi/Modules/YMRoom/View/MessageContainerView/View/XPRoomMessageTableViewCell.m +++ b/YuMi/Modules/YMRoom/View/MessageContainerView/View/XPRoomMessageTableViewCell.m @@ -27,14 +27,24 @@ @property (nonatomic,strong) XPNetImageYYLabel *contentLabel; ///点击空白区域的手势 @property (nonatomic,strong) UITapGestureRecognizer *tapEmptyRecognizer; + +@property(nonatomic, strong) UIVisualEffectView *blurEffectView; @end @implementation XPRoomMessageTableViewCell - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) { + if (isMSRTL()) { + self.semanticContentAttribute = UISemanticContentAttributeForceRightToLeft; + } [self initSubViews]; - [self initSubViewConstraints]; + if ([reuseIdentifier isEqualToString:@"XPRoomMessageTableViewCell_Boom"]) { + [self layoutBoom]; + } else { + [self layoutCell]; + } +// TODO:延迟聊天列表的加载时机,在房间信息确认后再加载 / 进房后首次加载可以尝试delay后二次刷新列表 } return self; } @@ -44,6 +54,7 @@ self.selectionStyle = UITableViewCellSelectionStyleNone; self.backgroundColor = [UIColor clearColor]; [self.contentView addSubview:self.bubbleImageView]; + [self.contentView addSubview:self.blurEffectView]; [self.contentView addSubview:self.contentLabel]; UITapGestureRecognizer * tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(didTap)]; tap.delegate = self; @@ -53,52 +64,84 @@ [self.contentView addSubview:self.leftBigImageView]; } -- (void)initSubViewConstraints { +- (void)layoutCell { + +// if (isMSRTL()){ +// [self.bubbleImageView mas_makeConstraints:^(MASConstraintMaker *make) { +// make.leading.mas_equalTo(10); +// make.top.mas_equalTo(self); +// make.width.mas_equalTo(kRoomMessageMaxWidth-10); +// make.bottom.mas_equalTo(self).offset(-10); +// }]; +// +// [self.contentLabel mas_makeConstraints:^(MASConstraintMaker *make) { +// make.leading.trailing.mas_equalTo(self).inset(15); +// make.centerY.mas_equalTo(self.bubbleImageView); +// }]; +// } else { + [self.bubbleImageView mas_makeConstraints:^(MASConstraintMaker *make) { + make.leading.top.mas_equalTo(self); + make.width.mas_equalTo(kRoomMessageMaxWidth-10); + make.trailing.mas_equalTo(self.contentLabel.mas_trailing).offset(-20); + make.bottom.mas_equalTo(self).offset(-10); + }]; + + [self.blurEffectView mas_makeConstraints:^(MASConstraintMaker *make) { + make.edges.mas_equalTo(self.bubbleImageView); + }]; + + [self.contentLabel mas_makeConstraints:^(MASConstraintMaker *make) { + make.leading.mas_equalTo(self).inset(10); + make.trailing.mas_greaterThanOrEqualTo(self.contentView).inset(10); + make.centerY.mas_equalTo(self.bubbleImageView); + }]; +// } + + return; +//TODO: 重新理解 layout 方案 + + [self.contentLabel mas_makeConstraints:^(MASConstraintMaker *make) { + make.edges.mas_equalTo(self.contentView); +// make.leading.mas_equalTo(12); +// make.bottom.mas_equalTo(-20); +// make.top.mas_equalTo(10); +// if (isMSRTL()) { +// make.width.mas_equalTo(20); +// } + }]; + [self.bubbleImageView mas_makeConstraints:^(MASConstraintMaker *make) { - make.leading.mas_equalTo(self.contentLabel).offset(-12); - make.top.mas_equalTo(self.contentLabel).offset(-10); - make.bottom.mas_equalTo(self.contentLabel).offset(10); - make.trailing.mas_equalTo(self.contentLabel).offset(10); + make.leading.mas_equalTo(self.contentLabel).offset(-12); + make.top.mas_equalTo(self.contentLabel).offset(-10); + make.bottom.mas_equalTo(self.contentLabel).offset(10); + make.trailing.mas_equalTo(self.contentLabel).offset(12); + }]; +} + +- (void)layoutBoom { + [self.bubbleImageView mas_makeConstraints:^(MASConstraintMaker *make) { + make.leading.mas_equalTo(0); + make.top.mas_equalTo(0); + make.bottom.mas_equalTo(-10); + make.trailing.mas_equalTo(self.contentLabel).offset(10); + }]; + + [self.leftBigImageView mas_makeConstraints:^(MASConstraintMaker *make) { + make.leading.mas_equalTo(0); + make.centerY.mas_equalTo(self.contentView); + make.size.mas_equalTo(CGSizeMake(50, 50)); }]; [self.contentLabel mas_makeConstraints:^(MASConstraintMaker *make) { - make.leading.mas_equalTo(12); - make.bottom.mas_equalTo(-20); - make.top.mas_equalTo(10); + make.leading.mas_equalTo(self.leftBigImageView.mas_trailing); + make.centerY.mas_equalTo(self.contentView); if (isMSRTL()) { make.width.mas_equalTo(20); } }]; } -- (void)setIsLeftBigImage:(BOOL)isLeftBigImage { - _isLeftBigImage = isLeftBigImage; - if (isLeftBigImage) { - - [self.bubbleImageView mas_remakeConstraints:^(MASConstraintMaker *make) { - make.leading.mas_equalTo(0); - make.top.mas_equalTo(0); - make.bottom.mas_equalTo(-10); - make.trailing.mas_equalTo(self.contentLabel).offset(10); - }]; - - [self.leftBigImageView mas_makeConstraints:^(MASConstraintMaker *make) { - make.leading.mas_equalTo(0); - make.centerY.mas_equalTo(self.contentView); - make.size.mas_equalTo(CGSizeMake(50, 50)); - }]; - - [self.contentLabel mas_remakeConstraints:^(MASConstraintMaker *make) { - make.leading.mas_equalTo(self.leftBigImageView.mas_trailing); - make.centerY.mas_equalTo(self.contentView); - if (isMSRTL()) { - make.width.mas_equalTo(20); - } - }]; - } -} - #pragma mark - tool - (UIImage*)resizableImage:(UIImage *)image { //图片拉伸区域 @@ -127,52 +170,72 @@ -(void)clickBtnAction{ } + + #pragma mark - Getters And Setters - (void)setMessageInfo:(XPMessageInfoModel *)messageInfo { _messageInfo = messageInfo; if (_messageInfo) { - self.contentLabel.attributedText = _messageInfo.content; + self.contentLabel.attributedText = messageInfo.content; - if (_messageInfo.bubbleImageUrl.length) { + if (messageInfo.bubbleImageUrl.length) { @kWeakify(self); - [self.bubbleImageView loadImageWithUrl:_messageInfo.bubbleImageUrl completion:^(UIImage * _Nonnull image, NSURL * _Nonnull url) { + [self.bubbleImageView loadImageWithUrl:messageInfo.bubbleImageUrl completion:^(UIImage * _Nonnull image, NSURL * _Nonnull url) { @kStrongify(self); + self.blurEffectView.hidden = YES; UIImage *image1 = [UIImage imageWithCGImage:image.CGImage scale:2.0 orientation:UIImageOrientationUp]; UIImage *cutImage = [image1 cropRightAndBottomPixels:2]; self.bubbleImageView.image = [self resizableImage:cutImage]; }]; - } - - if (self.isLeftBigImage) { + } else { + self.blurEffectView.hidden = NO; + self.bubbleImageView.image = [UIImage imageWithColor:[DJDKMIMOMColor messageBubbleColor]]; + } +/* +// [self.contentLabel mas_remakeConstraints:^(MASConstraintMaker *make) { +// make.leading.mas_equalTo(self.bubbleImageView).offset(_messageInfo.contentLeftMargin); +// make.trailing.mas_equalTo(self.bubbleImageView).offset(-_messageInfo.contentRightMargin); +// make.top.mas_equalTo(self.bubbleImageView).offset(_messageInfo.contentTopMargin); +// make.bottom.mas_equalTo(self.bubbleImageView).offset(-_messageInfo.contentBottomMargin); +// }]; + + if (self.isLeftBoomImage) { self.leftBigImageView.imageUrl = messageInfo.boomImageUrl; [self.contentLabel mas_updateConstraints:^(MASConstraintMaker *make) { make.leading.mas_equalTo(self.leftBigImageView.mas_trailing); make.trailing.mas_equalTo(-self.messageInfo.contentRightMargin - 8); -// make.centerY.mas_equalTo(self.contentView); make.top.mas_equalTo(self.bubbleImageView).offset(self.messageInfo.contentTopMargin); make.bottom.mas_equalTo(self.bubbleImageView).offset(-self.messageInfo.contentBottomMargin); -// if (isMSRTL()) { -// make.width.mas_equalTo([self RTLLabelWidth] - 65); -// } }]; } else { - [self.contentLabel mas_updateConstraints:^(MASConstraintMaker *make) { - make.leading.mas_equalTo(self.bubbleImageView).offset(self.messageInfo.contentLeftMargin); - make.top.mas_equalTo(self.bubbleImageView).offset(self.messageInfo.contentTopMargin); - make.bottom.mas_equalTo(self.bubbleImageView).offset(-self.messageInfo.contentBottomMargin); - if (isMSRTL()) { // MARK: 可能会有性能问题,但源代码已经使用了更新 layout 的方案,推测是头像框和气泡会导致卡顿 - make.width.mas_equalTo([self RTLLabelWidth]); - } + [self.contentLabel mas_remakeConstraints:^(MASConstraintMaker *make) { + make.leading.mas_equalTo(self.bubbleImageView).offset(_messageInfo.contentLeftMargin); +// if ([self RTLLabelWidth] <= 300) { +// make.width.mas_equalTo([self RTLLabelWidth]); +// } else { +// make.trailing.mas_equalTo(self.bubbleImageView).offset(-_messageInfo.contentRightMargin); +// } + make.top.mas_equalTo(self.bubbleImageView).offset(_messageInfo.contentTopMargin); + make.bottom.mas_equalTo(self.bubbleImageView).offset(-_messageInfo.contentBottomMargin); }]; +// [self.contentLabel mas_updateConstraints:^(MASConstraintMaker *make) { +// make.leading.mas_equalTo(self.bubbleImageView).offset(self.messageInfo.contentLeftMargin); +// make.top.mas_equalTo(self.bubbleImageView).offset(self.messageInfo.contentTopMargin); +// make.bottom.mas_equalTo(self.bubbleImageView).offset(-self.messageInfo.contentBottomMargin); +// if (isMSRTL()) { // MARK: 可能会有性能问题,但源代码已经使用了更新 layout 的方案,推测是头像框和气泡会导致卡顿 +// make.width.mas_equalTo([self RTLLabelWidth]); +//// make.width.mas_equalTo(messageInfo.textWidth); +// } +// }]; } - + */ _bubbleImageView.hidden = _messageInfo.isHiddenBubble; // [self layoutIfNeeded]; } } - (CGFloat)RTLLabelWidth { - return MIN(self.contentLabel.textWidth + self.messageInfo.contentLeftMargin + self.messageInfo.contentRightMargin + 8, self.contentLabel.maxWidth); + return MIN(self.contentLabel.textWidth + 88 + self.messageInfo.contentLeftMargin + self.messageInfo.contentRightMargin, self.contentLabel.maxWidth); } - (UIImage *)scaleToSize:(UIImage *)img { @@ -197,12 +260,28 @@ return; } if (_roomType == RoomType_MiniGame) { - _bubbleImageView.image = [UIImage imageWithColor:[UIColor colorWithWhite:1 alpha:0.2]]; + self.bubbleImageView.image = [UIImage imageWithColor:[UIColor colorWithWhite:1 alpha:0.2]]; } else { - _bubbleImageView.image = [UIImage imageWithColor:[DJDKMIMOMColor messageBubbleColor]]; + self.bubbleImageView.image = [UIImage imageWithColor:[DJDKMIMOMColor messageBubbleColor]]; } } +- (UIVisualEffectView *)blurEffectView { + if (!_blurEffectView) { + // 创建模糊效果 + UIBlurEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; // 选择模糊样式(例如:Light, Dark, ExtraLight 等) + + // 创建包含模糊效果的视图 + _blurEffectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect]; + + // 设置模糊视图的大小与目标视图一致 + _blurEffectView.frame = CGRectMake(0, 0, KScreenWidth, 200); + _blurEffectView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; // 使模糊视图适应目标视图的尺寸变化 + _blurEffectView.hidden = YES; + } + return _blurEffectView; +} + - (NetImageView *)bubbleImageView { if (!_bubbleImageView) { diff --git a/YuMi/Modules/YMRoom/View/MessageContainerView/XPRoomMessageContainerView.m b/YuMi/Modules/YMRoom/View/MessageContainerView/XPRoomMessageContainerView.m index 3600ad6b..96b2aa4b 100644 --- a/YuMi/Modules/YMRoom/View/MessageContainerView/XPRoomMessageContainerView.m +++ b/YuMi/Modules/YMRoom/View/MessageContainerView/XPRoomMessageContainerView.m @@ -45,6 +45,8 @@ #import "SDPhotoBrowser.h" #import "XPSkillCardPlayerManager.h" +#import "RoomCahtCell.h" + // Boom #import "BoomInfoModel.h" @@ -82,6 +84,10 @@ NSString * const kRoomShowTopicKey = @"kRoomShowTopicKey"; @property(nonatomic,assign) BOOL isLoadHistoryMessage; @property (nonatomic, assign) NSInteger displayType; + +@property (nonatomic, strong) NSMutableDictionary *heightCache; +@property (nonatomic, strong) NSMutableDictionary *heightCache_2; + @end @@ -94,6 +100,8 @@ NSString * const kRoomShowTopicKey = @"kRoomShowTopicKey"; - (instancetype)initWithDelegate:(id)delegate { self = [super init]; if (self) { + self.heightCache = @{}.mutableCopy; + self.heightCache_2 = @{}.mutableCopy; self.displayType = 1; self.isLoadHistoryMessage = YES; self.hostDelegate = delegate; @@ -323,7 +331,7 @@ NSString * const kRoomShowTopicKey = @"kRoomShowTopicKey"; }]; [self.messageTipsBtn mas_makeConstraints:^(MASConstraintMaker *make) { - make.width.mas_equalTo(100); + make.width.mas_greaterThanOrEqualTo(100); make.height.mas_equalTo(30); make.bottom.mas_equalTo(self.mas_bottom).offset(-5); make.leading.mas_equalTo(self); @@ -379,7 +387,6 @@ NSString * const kRoomShowTopicKey = @"kRoomShowTopicKey"; } } - if (self.isPending) { self.messageTipsBtn.hidden = NO; [self findAtMeNumber]; @@ -402,12 +409,9 @@ NSString * const kRoomShowTopicKey = @"kRoomShowTopicKey"; [self.datasource removeObjectsInArray:needRemoveMsgArray]; } - // 执行插入 - // for (NIMMessage *item in self.incomingMessages) { - // XPMessageInfoModel *model = [self.messageParser parseMessageAttribute:item]; - // [self.datasource addObject:model]; - // } + @kWeakify(self); [self.incomingMessages enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { + @kStrongify(self); if ([obj isKindOfClass:[NIMMessage class]]) { XPMessageInfoModel *model = [self.messageParser parseMessageAttribute:(NIMMessage *)obj]; [self.datasource addObject:model]; @@ -872,7 +876,7 @@ NSString * const kRoomShowTopicKey = @"kRoomShowTopicKey"; option.messageTypes = @[@(NIMMessageTypeText),@(NIMMessageTypeCustom)]; [[NIMSDK sharedSDK].chatroomManager fetchMessageHistory:roomId option:option result:^(NSError * _Nullable error, NSArray * _Nullable messages) { if(error != nil){ - self.isLoadHistoryMessage = NO; + self.isLoadHistoryMessage = NO; } if (messages.count) { //如果拉取的数量等于请求的数量,说明这个时间点以后的消息数量大于等于需要拉取的数量,直接拉取最新的50条 @@ -957,7 +961,6 @@ NSString * const kRoomShowTopicKey = @"kRoomShowTopicKey"; [self createUserEnterRoomAddRoomTopicMessage]; }); } - }]; } -(void)dealWithHistoryDataWithMessage:(NIMMessage *)item{ @@ -971,7 +974,6 @@ NSString * const kRoomShowTopicKey = @"kRoomShowTopicKey"; if (attachment.first == CustomMessageType_Room_Album && attachment.second == Custom_Message_Sub_Room_Album) { isHaveSave = YES; } - } } if(isHaveSave == NO)return; @@ -1034,7 +1036,7 @@ NSString * const kRoomShowTopicKey = @"kRoomShowTopicKey"; } - (void)onRoomEntered { - [[XPRoomMiniManager shareManager] resetLocalMessage]; + [[XPRoomMiniManager shareManager] resetLocalMessage]; self.headerView.bubbleColor = self.hostDelegate.getRoomInfo.type == RoomType_MiniGame ? [UIColor colorWithWhite:1 alpha:0.2] : [UIColor colorWithWhite:1 alpha:0.3]; } @@ -1096,14 +1098,35 @@ NSString * const kRoomShowTopicKey = @"kRoomShowTopicKey"; #pragma mark - UITableViewDelegate And UITableViewDataSource + - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { NSArray *source = @[]; switch (self.displayType) { - case 1: + case 1: { source = self.datasource; + XPMessageInfoModel *model = [source xpSafeObjectAtIndex:indexPath.row]; + NSNumber *cacheHeight = self.heightCache[indexPath]; + if (cacheHeight) { + return cacheHeight.floatValue; + } else { + CGFloat height = [self calculateHeightForMessage:model]; + self.heightCache[indexPath] = @(height); + return height; + } + } break; - case 2: + case 2: { source = self.datasource_chat; + XPMessageInfoModel *model = [source xpSafeObjectAtIndex:indexPath.row]; + NSNumber *cacheHeight = self.heightCache_2[indexPath]; + if (cacheHeight) { + return cacheHeight.floatValue; + } else { + CGFloat height = [self calculateHeightForMessage:model]; + self.heightCache_2[indexPath] = @(height); + return height; + } + } break; case 3: source = self.datasource_gift; @@ -1114,17 +1137,21 @@ NSString * const kRoomShowTopicKey = @"kRoomShowTopicKey"; break; } - XPMessageInfoModel *model = [source xpSafeObjectAtIndex:indexPath.row]; + - // 如果 model 中有高度数据,使用 model 的高度 - if (model.rowHeight > 0) { - return model.rowHeight; - } +// // 如果 model 中有高度数据,使用 model 的高度 +// if (model.rowHeight > 0) { +//// NSLog(@"---00--- : %f", model.rowHeight); +// return model.rowHeight; +// } + + // 否则,使用自适应高度 return UITableViewAutomaticDimension; } + - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { switch (self.displayType) { case 1: @@ -1173,38 +1200,51 @@ NSString * const kRoomShowTopicKey = @"kRoomShowTopicKey"; cellKey = @"XPRoomMessageTableViewCell_Boom"; } - XPRoomMessageTableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:cellKey]; - cell.delegate = self; - cell.isLeftBigImage = model.isBoom; + RoomCahtCell *cell = [RoomCahtCell cellFor:tableView]; cell.messageInfo = model; - cell.roomType = self.hostDelegate.getRoomInfo.type; + +// XPRoomMessageTableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:cellKey]; +// cell.delegate = self; +// cell.isLeftBoomImage = model.isBoom; +// cell.messageInfo = model; +// cell.roomType = self.hostDelegate.getRoomInfo.type; return cell; } -- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath { -// NSArray *source = @[]; -// switch (self.displayType) { -// case 1: -// source = self.datasource; -// break; -// case 2: -// source = self.datasource_chat; -// break; -// case 3: -// source = self.datasource_gift; -// break; -// -// default: -// source = self.datasource; -// break; -// } -// XPMessageInfoModel *model = [source xpSafeObjectAtIndex:indexPath.row]; -// if (model.rowHeight == 0) { -// model.rowHeight = CGRectGetHeight(cell.frame); -// } -} +- (CGFloat)calculateHeightForMessage:(XPMessageInfoModel *)messageInfo { + if (!messageInfo) return 60; // 返回默认高度 + CGFloat totalHeight = 0; + + // 1. 计算富文本内容的高度 + NSMutableAttributedString *content = [[NSMutableAttributedString alloc] initWithAttributedString:messageInfo.content]; + CGFloat maxWidth = kRoomMessageMaxWidth - 24; // 内容最大宽度 + CGSize boundingSize = CGSizeMake(maxWidth, CGFLOAT_MAX); + + YYTextContainer *textContainer = [YYTextContainer containerWithSize:boundingSize]; + YYTextLayout *textLayout = [YYTextLayout layoutWithContainer:textContainer text:content]; + totalHeight += textLayout.textBoundingSize.height; + +// // 2. 计算图片的高度(如果存在图片) +// if (messageInfo.bubbleImageUrl && !messageInfo.isHiddenBubble) { +// UIImage *cachedImage = [[SDImageCache sharedImageCache] imageFromDiskCacheForKey:messageInfo.bubbleImageUrl]; +// if (cachedImage) { +// CGFloat imageWidth = cachedImage.size.width; +// CGFloat imageHeight = cachedImage.size.height; +// CGFloat scale = imageWidth / imageHeight; +// CGFloat adjustedImageHeight = maxWidth / scale; // 根据宽度调整高度 +// totalHeight += adjustedImageHeight; +// } else { +// // 如果图片尚未加载,使用默认占位高度 +// totalHeight += 100; // 默认图片高度 +// } +// } + + // 3. 加上内边距 + totalHeight += 16 * 2; // 顶部和底部的 padding + return totalHeight; +} #pragma mark - XPRoomMessageTableViewCellDelegate - (void)xPRoomMessageTableViewCellDidTapEmpty:(XPRoomMessageTableViewCell *)view { @@ -1246,7 +1286,6 @@ NSString * const kRoomShowTopicKey = @"kRoomShowTopicKey"; - (void)unlockRoomAlbumImageWithAlbumModel:(PIRoomPhotoAlbumItemModel *)albumModel{ [XNDJTDDLoadingTool showLoading]; [Api unlockRoomAlbumPhoto:^(BaseModel * _Nullable data, NSInteger code, NSString * _Nullable msg) { - [XNDJTDDLoadingTool hideHUD]; if(code == 200){ NSMutableDictionary *getData = [NSMutableDictionary dictionary]; @@ -1314,7 +1353,7 @@ NSString * const kRoomShowTopicKey = @"kRoomShowTopicKey"; _messageTableView.delegate = self; _messageTableView.dataSource = self; _messageTableView.rowHeight = UITableViewAutomaticDimension; - _messageTableView.estimatedRowHeight = 44; // 预估高度 + _messageTableView.estimatedRowHeight = 100; // 预估高度 _messageTableView.tableFooterView = [UIView new]; _messageTableView.separatorStyle = UITableViewCellSeparatorStyleNone; _messageTableView.backgroundColor = [UIColor clearColor]; @@ -1327,6 +1366,7 @@ NSString * const kRoomShowTopicKey = @"kRoomShowTopicKey"; [_messageTableView registerClass:[XPRoomMessageTableViewCell class] forCellReuseIdentifier:NSStringFromClass([XPRoomMessageTableViewCell class])]; [_messageTableView registerClass:[PIRoomMessagePhotoAlbumCell class] forCellReuseIdentifier:NSStringFromClass([PIRoomMessagePhotoAlbumCell class])]; + [RoomCahtCell registerTo:_messageTableView]; } return _messageTableView; } diff --git a/YuMi/Modules/YMRoom/View/RoomGame/View/SubView/MSRoomGameMsgView.m b/YuMi/Modules/YMRoom/View/RoomGame/View/SubView/MSRoomGameMsgView.m index d5f14eb7..08a32f6f 100644 --- a/YuMi/Modules/YMRoom/View/RoomGame/View/SubView/MSRoomGameMsgView.m +++ b/YuMi/Modules/YMRoom/View/RoomGame/View/SubView/MSRoomGameMsgView.m @@ -234,8 +234,6 @@ return self.datasource.count; } - - - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { XPMessageInfoModel* attr = [self.datasource xpSafeObjectAtIndex:indexPath.row]; @@ -244,8 +242,6 @@ cell.messageInfo = attr; return cell; - - } diff --git a/YuMi/Modules/YMRoom/View/ThemeColor+Room.m b/YuMi/Modules/YMRoom/View/ThemeColor+Room.m index 2665c7aa..1152912d 100644 --- a/YuMi/Modules/YMRoom/View/ThemeColor+Room.m +++ b/YuMi/Modules/YMRoom/View/ThemeColor+Room.m @@ -53,7 +53,7 @@ ///公屏默认背景的颜色 + (UIColor *)messageBubbleColor { - return UIColorRGBAlpha(0xFFFFFF, 0.15); + return UIColorRGBAlpha(0xFFFFFF, 0.35); } ///公屏文字的颜色 + (UIColor *)messageTextColor {