项目要求实现“翻译”的功能,融云 SDK 本身没这个功能,所以只能曲线救国了,通过自定义消息来实现,下面是功能实现相关内容。
资源链接:
官网:https://www.rongcloud.cn/
自定义消息文档:https://docs.rongcloud.cn/v4/views/im/ui/guide/private/conversation/msgsend/ios.html#createcustom
实现思路
- 创建自定义 cell,与 SDK 内置的文本消息进行绑定。因为他们内置的文本消息 cell 不支持扩展显示翻译的内容,所以需要使用自定义 cell。
- 在聊天页面将自定义 cell 与内置的文本消息进行绑定。
- 重写长按消息 cell 的方法,判断如果是文本消息,增加“翻译”按钮。
- 点击“翻译”按钮,对文本内容进行翻译,并将翻译好的内容设置到数据源中。
- 刷新 UI,会触发自定义 cell 中的回调方法,在回调方法中重新设置高度,并添加 UI,对数据源中翻译好的内容进行展示。
代码部分
-
创建自定义 cell 继承于 RCTextMessageCell,m 文件中代码如下,具体效果可自行调整
#import "RCDTextMessageCell.h" #define RCDScreenWidth [UIScreen mainScreen].bounds.size.width #define Font_Size 16 #define Extra_BackgroupView_CornerRadius 6.f @interface RCDTextMessageCell () //翻译内容的 Label @property (strong, nonatomic) UILabel *extraLabel; //翻译内容的背景图 @property (strong, nonatomic) UIView *extraBackgroundView; @end @implementation RCDTextMessageCell + (CGSize)sizeForMessageModel:(RCMessageModel *)model withCollectionViewWidth:(CGFloat)collectionViewWidth referenceExtraHeight:(CGFloat)extraHeight { //翻译好的内容 NSString *extra = model.extra; CGSize superSize = [super sizeForMessageModel:model withCollectionViewWidth:collectionViewWidth referenceExtraHeight:extraHeight]; if (extra.length > 0) { CGSize extraSize = [RCDTextMessageCell getTextLabelSize:extra]; CGFloat finalHeight = superSize.height + extraSize.height; return CGSizeMake(superSize.width, finalHeight); }else { return superSize; } } //计算文本 size 的方法 + (CGSize)getTextLabelSize:(NSString *)content { if ([content length] > 0) { float maxWidth = RCDScreenWidth - (10 + [RCIM sharedRCIM].globalMessagePortraitSize.width + 10) * 2 - 5 - 35; CGRect textRect = [content boundingRectWithSize:CGSizeMake(maxWidth, 8000) options:(NSStringDrawingTruncatesLastVisibleLine | NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading) attributes:@{NSFontAttributeName : [UIFont systemFontOfSize:Font_Size]} context:nil]; textRect.size.height = ceilf(textRect.size.height); textRect.size.width = ceilf(textRect.size.width); return CGSizeMake(textRect.size.width + 5, textRect.size.height + 5); } else { return CGSizeZero; } } - (void)setDataModel:(RCMessageModel *)model { [super setDataModel:model]; NSString *extra = model.extra; //为了防止复用问题的处理 [self.extraLabel removeFromSuperview]; [self.extraBackgroundView removeFromSuperview]; //如果有翻译的内容,添加 UI,进行展示 if (extra.length > 0) { CGSize extraSize = [[self class] getTextLabelSize:extra]; CGRect superFrame = self.bubbleBackgroundView.frame; CGRect extraBackgroundViewFrame = CGRectZero; //判断消息方向,设置翻译背景图的 frame if (model.messageDirection == MessageDirection_SEND) { extraBackgroundViewFrame = CGRectMake(superFrame.origin.x + superFrame.size.width - extraSize.width - 15, superFrame.size.height + 3, extraSize.width + 10, extraSize.height + 6); } else { extraBackgroundViewFrame = CGRectMake(superFrame.origin.x + 5, superFrame.origin.y + superFrame.size.height + 3, extraSize.width + 10, extraSize.height + 6); } self.extraBackgroundView = [[UIView alloc] initWithFrame:extraBackgroundViewFrame]; self.extraBackgroundView.backgroundColor = [UIColor whiteColor]; self.extraBackgroundView.layer.cornerRadius = Extra_BackgroupView_CornerRadius; [self.messageContentView addSubview:self.extraBackgroundView]; CGRect extraLabelFrame = CGRectMake(8, 3, extraSize.width, extraSize.height); self.extraLabel = [[UILabel alloc] initWithFrame:extraLabelFrame]; self.extraLabel.font = [UIFont systemFontOfSize:Font_Size]; self.extraLabel.numberOfLines = 0; [self.extraLabel setLineBreakMode:NSLineBreakByWordWrapping]; [self.extraLabel setTextAlignment:NSTextAlignmentLeft]; [self.extraBackgroundView addSubview:self.extraLabel]; self.extraLabel.text = extra; } } @end
-
在聊天页面类导入并绑定自定义 cell :
#import "RCDTextMessageCell.h" - (void)viewDidLoad { [super viewDidLoad]; [self registerClass:[RCDTextMessageCell class] forMessageClass:[RCTextMessage class]]; }
-
在聊天页面实现长按消息的“翻译”方法:
- 创建一个属性用于暂存长按时候的 model。
@property (strong, nonatomic) RCMessageModel *longTouchModel;
-
重写长按消息 cell 的方法,判断如果是文本消息,增加“翻译”按钮,translate 是实现“翻译”的方法。
- (NSArray
*)getLongTouchMessageCellMenuList:(RCMessageModel *)model { NSMutableArray *menuList = [[super getLongTouchMessageCellMenuList:model] mutableCopy]; if ([model.content isKindOfClass:[RCTextMessage class]]) { UIMenuItem *forwardItem = [[UIMenuItem alloc] initWithTitle:@"翻译" action:@selector(translate)]; self.longTouchModel = model; [menuList addObject:forwardItem]; } return menuList; }
-
实现“翻译”方法,并将翻译好的内容设置到数据源中:
- 代码仅供参考,翻译的方法还需要自己来实现,把最终翻译好的结果赋值给 self.longTouchModel.extra
- 这里必须要提的是 cellSize = CGSizeZero,否则刷新 UI 不会改变 cell 的高度
- 刷新 self.conversationMessageCollectionView
- 如果翻译的是最后一条消息,需要滚动到底部,否则翻译的内容会被遮挡
- (void)translate { if (self.longTouchModel) { NSString *result = @"翻译后的结果。"; RCTextMessage *txtMsg = (RCTextMessage *)self.longTouchModel.content; if ([txtMsg.content isEqualToString:@"How are you?"]) { result = @"你好吗?"; } else if ([txtMsg.content isEqualToString:@"I’m fine."]) { result = @"我很好。"; } self.longTouchModel.extra = result; self.longTouchModel.cellSize = CGSizeZero; [self.conversationMessageCollectionView reloadData]; RCMessageModel *model = [self.conversationDataRepository lastObject]; if (model.messageId == self.longTouchModel.messageId ) { [self scrollToBottomAnimated:YES]; } } }
刷新 UI 时,显示翻译的内容,自定义 cell 会回调设置 CGSize 的方法,改变 cell 高度,同时也会回调 setDataModel 方法,在这个方法中添加翻译的内容,具体可以参考自定义 cell 的 m 文件中代码,这里就不重复贴代码了。
到此为止,该功能已经算是搞定了,同样这个思路和处理方法也适用于“语音转文字”,把翻译功能换成语音转文字,cell 继承于 RCVoiceMessageCell 就完了,希望这篇分享能帮助到大家。