You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

624 lines
27 KiB

//
// XHMessageBubbleView.m
// MessageDisplayExample
//
// Created by HUAJIE-1 on 14-4-24.
// Copyright (c) 2014年 曾宪华 开发团队(http://iyilunba.com ) 本人QQ:543413507 本人QQ群(142557668). All rights reserved.
//
#import "XHMessageBubbleView.h"
#import "XHMessageBubbleHelper.h"
#import "XHConfigurationHelper.h"
#import "myHelper.h"
#define kXHHaveBubbleMargin 5.0f // 文本、视频、表情气泡上下边的间隙
#define kXHHaveBubbleVoiceMargin 5 // 语音气泡上下边的间隙
#define kXHHaveBubblePhotoMargin 6.5f // 图片、地理位置气泡上下边的间隙
#define kXHVoiceMargin 20.0f // 播放语音时的动画控件距离头像的间隙
#define kXHArrowMarginWidth 5.2f // 箭头宽度
#define kXHTopAndBottomBubbleMargin 10.0f // 文本在气泡内部的上下间隙
#define kXHLeftTextHorizontalBubblePadding 8.0f // 文本的水平间隙
#define kXHRightTextHorizontalBubblePadding 8.0f // 文本的水平间隙
#define kXHUnReadDotSize 7.0f // 语音未读的红点大小
#define kXHNoneBubblePhotoMargin (kXHHaveBubbleMargin - kXHBubblePhotoMargin) // 在没有气泡的时候,也就是在图片、视频、地理位置的时候,图片内部做了Margin,所以需要减去内部的Margin
@interface XHMessageBubbleView ()
@property (nonatomic, weak, readwrite) SETextView *displayTextView;
@property (nonatomic, weak, readwrite) UIImageView *bubbleImageView;
@property (nonatomic, weak, readwrite) FLAnimatedImageView *emotionImageView;
@property (nonatomic, weak, readwrite) UIImageView *animationVoiceImageView;
@property (nonatomic, weak, readwrite) UIImageView *voiceUnreadDotImageView;
@property (nonatomic, weak, readwrite) UILabel *voiceDurationLabel;
@property (nonatomic, weak, readwrite) XHBubblePhotoImageView *bubblePhotoImageView;
@property (nonatomic, weak, readwrite) UIImageView *videoPlayImageView;
@property (nonatomic, weak, readwrite) UILabel *geolocationsLabel;
@property (nonatomic, strong, readwrite) XHMessage * message;
@end
@implementation XHMessageBubbleView
#pragma mark - Bubble view
// 获取文本的实际大小
+ (CGFloat)neededWidthForText:(NSString *)text {
UIFont *systemFont = [[XHMessageBubbleView appearance] font];
CGSize textSize = CGSizeMake(CGFLOAT_MAX, 20); // rough accessory size
CGSize sizeWithFont = [text sizeWithFont:systemFont constrainedToSize:textSize lineBreakMode:NSLineBreakByWordWrapping];
#if defined(__LP64__) && __LP64__
return ceil(sizeWithFont.width);
#else
return ceilf(sizeWithFont.width);
#endif
}
// 计算文本实际的大小
+ (CGSize)neededSizeForText:(NSString *)text {
// 实际处理文本的时候
// 文本只有一行的时候,宽度可能出现很小到最大的情况,所以需要计算一行文字需要的宽度
CGFloat maxWidth = CGRectGetWidth([[UIScreen mainScreen] bounds]) * (kIsiPad ? 0.8 : (kIs_iPhone_6 ? 0.6 : (kIs_iPhone_6P ? 0.62 : 0.55)));
CGFloat dyWidth = [XHMessageBubbleView neededWidthForText:text];
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 9.0) {
dyWidth += 5;
}
CGSize textSize = [SETextView frameRectWithAttributtedString:[[XHMessageBubbleHelper sharedMessageBubbleHelper] bubbleAttributtedStringWithText:text]
constraintSize:CGSizeMake(maxWidth, MAXFLOAT)
lineSpacing:kXHTextLineSpacing
font:[[XHMessageBubbleView appearance] font]].size;
return CGSizeMake((dyWidth > textSize.width ? textSize.width : dyWidth), textSize.height);
}
// 计算图片实际大小
+ (CGSize)neededSizeForPhoto:(UIImage *)photo {
// 这里需要缩放后的size
CGSize photoSize = CGSizeMake(140, 140);
return photoSize;
}
// 计算语音实际大小
+ (CGSize)neededSizeForVoicePath:(NSString *)voicePath voiceDuration:(NSString *)voiceDuration {
#warning Here we define the width of a speech over 15s in terms of the length of 15s
//这里定义超过15s 语音的按照15s 的时长来计算宽度
if([voiceDuration floatValue] > 15){
voiceDuration = @"15";
}
// 这里的100只是暂时固定,到时候会根据一个函数来计算
float gapDuration = (!voiceDuration || voiceDuration.length == 0 ? -1 : [voiceDuration floatValue] - 1.0f);
CGSize voiceSize = CGSizeMake(100 + (gapDuration > 0 ? (120.0 / (kVoiceRecorderTotalTime - 1) * gapDuration) : 0), 42);
return voiceSize;
}
// 计算Emotion的高度
+ (CGSize)neededSizeForEmotion {
return CGSizeMake(100, 100);
}
// 计算LocalPostion的高度
+ (CGSize)neededSizeForLocalPostion {
return CGSizeMake(140, 140);
}
// 判断问文字消息内容是否是中文
+ (BOOL)IsChinese:(NSString *)str
{
for(int i=0; i< [str length];i++)
{
int a = [str characterAtIndex:i];
if( a > 0x4e00 && a < 0x9fff)
{
return YES;
}
}
return NO;
}
// 计算Cell需要实际Message内容的大小
+ (CGFloat)calculateCellHeightWithMessage:(XHMessage *)message {
CGSize size = [XHMessageBubbleView getBubbleFrameWithMessage:message];
return size.height;
}
// 获取Cell需要的高度
+ (CGSize)getBubbleFrameWithMessage:(XHMessage *)message {
CGSize bubbleSize;
switch (message.messageMediaType) {
case XHBubbleMessageMediaTypeText: {
CGFloat ise = [self IsChinese:message.content] ? 2 : 5;
CGSize needTextSize = [XHMessageBubbleView neededSizeForText:message.content];
bubbleSize = CGSizeMake(needTextSize.width + kXHLeftTextHorizontalBubblePadding + kXHRightTextHorizontalBubblePadding , needTextSize.height + kXHHaveBubbleMargin * 2 + kXHTopAndBottomBubbleMargin * 2 + ise); //这里*4的原因是:气泡内部的文本也做了margin,而且margin的大小和气泡的margin一样大小,所以需要加上*2的间隙大小
break;
}
case XHBubbleMessageMediaTypeVoice: {
// 这里的宽度是不定的,高度是固定的,根据需要根据语音长短来定制啦
CGSize needVoiceSize = [XHMessageBubbleView neededSizeForVoicePath:message.voicePath voiceDuration:[NSString stringWithFormat:@"%d",[message.duration intValue]]];
bubbleSize = CGSizeMake(needVoiceSize.width, needVoiceSize.height + kXHHaveBubbleVoiceMargin * 2);
break;
}
case XHBubbleMessageMediaTypeEmotion: {
// 是否固定大小呢?
CGSize emotionSize = [XHMessageBubbleView neededSizeForEmotion];
bubbleSize = CGSizeMake(emotionSize.width, emotionSize.height + kXHHaveBubbleMargin * 2);
break;
}
case XHBubbleMessageMediaTypeVideo: {
CGSize needVideoConverPhotoSize = [XHMessageBubbleView neededSizeForPhoto:message.videoConverPhoto];
bubbleSize = CGSizeMake(needVideoConverPhotoSize.width, needVideoConverPhotoSize.height + kXHNoneBubblePhotoMargin * 2);
break;
}
case XHBubbleMessageMediaTypePhoto: {
CGSize needPhotoSize = [XHMessageBubbleView neededSizeForPhoto:message.photo];
bubbleSize = CGSizeMake(needPhotoSize.width, needPhotoSize.height + kXHHaveBubblePhotoMargin * 3);
break;
}
case XHBubbleMessageMediaTypeLocalPosition: {
// 固定大小,必须的
CGSize localPostionSize = [XHMessageBubbleView neededSizeForLocalPostion];
bubbleSize = CGSizeMake(localPostionSize.width, localPostionSize.height + kXHHaveBubblePhotoMargin * 2);
break;
}
default:
break;
}
return bubbleSize;
}
#pragma mark - UIAppearance Getters
- (UIFont *)font {
if (_font == nil) {
_font = [[[self class] appearance] font];
}
if (_font != nil) {
return _font;
}
return [UIFont systemFontOfSize:16.0f];
}
#pragma mark - Getters
// 获取气泡的位置以及大小,比如有文字的气泡,语音的气泡,图片的气泡,地理位置的气泡,Emotion的气泡,视频封面的气泡
- (CGRect)bubbleFrame
{
// 1.先得到MessageBubbleView的实际大小
CGSize bubbleSize = [XHMessageBubbleView getBubbleFrameWithMessage:self.message];
// 2.计算起泡的大小和位置
CGFloat paddingX = 0.0f;
if (self.message.bubbleMessageType == XHBubbleMessageTypeSending) {
paddingX = CGRectGetWidth(self.bounds) - bubbleSize.width;
}
XHBubbleMessageMediaType currentMessageMediaType = self.message.messageMediaType;
// 最终减去上下边距的像素就可以得到气泡的位置以及大小
CGFloat marginY = kXHHaveBubbleVoiceMargin;
CGFloat topSumForBottom = 0.0;
switch (currentMessageMediaType) {
case XHBubbleMessageMediaTypeVoice:
// marginY = kXHHaveBubbleVoiceMargin;
topSumForBottom = kXHHaveBubbleVoiceMargin * 2;
break;
case XHBubbleMessageMediaTypePhoto:
case XHBubbleMessageMediaTypeLocalPosition:
// marginY = kXHHaveBubblePhotoMargin;
topSumForBottom = kXHHaveBubblePhotoMargin * 2;
break;
case XHBubbleMessageMediaTypeText:
topSumForBottom = 10 * 2;
break;
default:
// 视频、表情
marginY = kXHHaveBubbleMargin;
topSumForBottom = kXHHaveBubbleMargin * 2;
break;
}
return CGRectMake(paddingX,
marginY,
bubbleSize.width,
bubbleSize.height - topSumForBottom);
}
#pragma mark - Configure Methods
- (void)configureCellWithMessage:(XHMessage *)message {
_message = message;
[self configureBubbleImageView:message];
[self configureMessageDisplayMediaWithMessage:message];
}
- (void)configureBubbleImageView:(XHMessage *)message {
XHBubbleMessageMediaType currentType = message.messageMediaType;
_voiceDurationLabel.hidden = YES;
_voiceUnreadDotImageView.hidden = YES;
switch (currentType) {
case XHBubbleMessageMediaTypeVoice: {
// update by lsz 隐藏语音时间 NO ==》 YES
_voiceDurationLabel.hidden = NO;
_voiceUnreadDotImageView.hidden = message.isRead;
}
case XHBubbleMessageMediaTypeText:
case XHBubbleMessageMediaTypeEmotion: {
_bubbleImageView.image = [XHMessageBubbleFactory bubbleImageViewForType:message.bubbleMessageType style:XHBubbleImageViewStyleWeChat meidaType:message.messageMediaType];
// 只要是文本、语音、第三方表情,背景的气泡都不能隐藏
_bubbleImageView.hidden = NO;
// add by lsz 20201206
if (@available(iOS 14.0, *)) {
if (message.bubbleMessageType == XHBubbleMessageTypeSending) {
_bubbleImageView.layer.cornerRadius = 5.0f;
_bubbleImageView.layer.masksToBounds = YES;
_bubbleImageView.backgroundColor = RGBA(255, 230, 218, 1); /// 气泡背景颜色
} else {
_bubbleImageView.backgroundColor = [UIColor whiteColor];
_bubbleImageView.layer.cornerRadius = 5.0f;
_bubbleImageView.layer.masksToBounds = YES;
}
}
// 只要是文本、语音、第三方表情,都需要把显示尖嘴图片的控件隐藏了
_bubblePhotoImageView.hidden = YES;
if (currentType == XHBubbleMessageMediaTypeText) {
// 如果是文本消息,那文本消息的控件需要显示
_displayTextView.hidden = NO;
if(message.bubbleMessageType == XHBubbleMessageTypeSending){
_displayTextView.textColor = KKBlack20;
}else{
_displayTextView.textColor = KKBlack20;
}
// 那语言的gif动画imageView就需要隐藏了
_animationVoiceImageView.hidden = YES;
_emotionImageView.hidden = YES;
}
else
{
// 那如果不文本消息,必须把文本消息的控件隐藏了啊
_displayTextView.hidden = YES;
// 对语音消息的进行特殊处理,第三方表情可以直接利用背景气泡的ImageView控件
if (currentType == XHBubbleMessageMediaTypeVoice) {
[_animationVoiceImageView removeFromSuperview];
_animationVoiceImageView = nil;
UIImageView *animationVoiceImageView = [XHMessageVoiceFactory messageVoiceAnimationImageViewWithBubbleMessageType:message.bubbleMessageType];
[self addSubview:animationVoiceImageView];
_animationVoiceImageView = animationVoiceImageView;
_animationVoiceImageView.hidden = NO;
} else {
_emotionImageView.hidden = NO;
_bubbleImageView.hidden = YES;
_animationVoiceImageView.hidden = YES;
}
}
break;
}
case XHBubbleMessageMediaTypePhoto:
case XHBubbleMessageMediaTypeVideo:
case XHBubbleMessageMediaTypeLocalPosition: {
// 只要是图片和视频消息,必须把尖嘴显示控件显示出来
_bubblePhotoImageView.hidden = NO;
_videoPlayImageView.hidden = (currentType != XHBubbleMessageMediaTypeVideo);
_geolocationsLabel.hidden = (currentType != XHBubbleMessageMediaTypeLocalPosition);
// 那其他的控件都必须隐藏
_displayTextView.hidden = YES;
_bubbleImageView.hidden = YES;
_animationVoiceImageView.hidden = YES;
_emotionImageView.hidden = YES;
break;
}
default:
break;
}
}
- (void)configureMessageDisplayMediaWithMessage:(XHMessage *)message {
switch (message.messageMediaType) {
case XHBubbleMessageMediaTypeText:
_displayTextView.attributedText = [[XHMessageBubbleHelper sharedMessageBubbleHelper] bubbleAttributtedStringWithText:message.content];
break;
case XHBubbleMessageMediaTypePhoto:
_bubblePhotoImageView.message = message;
[_bubblePhotoImageView configureMessagePhoto:message.photo thumbnailUrl:message.content originPhotoUrl:message.content onBubbleMessageType:self.message.bubbleMessageType];
break;
case XHBubbleMessageMediaTypeVideo:
[_bubblePhotoImageView configureMessagePhoto:message.videoConverPhoto thumbnailUrl:message.content originPhotoUrl:message.content onBubbleMessageType:self.message.bubbleMessageType];
break;
case XHBubbleMessageMediaTypeVoice:
self.voiceDurationLabel.text = [NSString stringWithFormat:@"%d\'\'", [message.duration intValue]];
break;
case XHBubbleMessageMediaTypeEmotion:
// 直接设置GIF
if (message.content) {
NSString *imgStr = [NSString stringWithFormat:@"emoji_%@",message.content];
NSData *animatedData = UIImagePNGRepresentation(ImageName_(imgStr));
//NSData *animatedData = [NSData dataWithContentsOfFile:message.emotionPath];
FLAnimatedImage *animatedImage = [[FLAnimatedImage alloc] initWithAnimatedGIFData:animatedData];
_emotionImageView.animatedImage = animatedImage;
}
break;
case XHBubbleMessageMediaTypeLocalPosition:
[_bubblePhotoImageView configureMessagePhoto:message.localPositionPhoto thumbnailUrl:nil originPhotoUrl:nil onBubbleMessageType:self.message.bubbleMessageType];
_geolocationsLabel.text = message.geolocations;
break;
default:
break;
}
[self setNeedsLayout];
}
- (void)configureVoiceDurationLabelFrameWithBubbleFrame:(CGRect)bubbleFrame {
CGRect voiceFrame = _voiceDurationLabel.frame;
voiceFrame.origin.x = (self.message.bubbleMessageType == XHBubbleMessageTypeSending ? bubbleFrame.origin.x - CGRectGetWidth(voiceFrame) : bubbleFrame.origin.x + bubbleFrame.size.width);
// voiceFrame.origin.y = _bubbleImageView.frame.origin.y;xTT_chat
_voiceDurationLabel.frame = voiceFrame;
_voiceDurationLabel.center = CGPointMake(_voiceDurationLabel.center.x,
_bubbleImageView.center.y);
}
- (void)configureVoiceUnreadDotImageViewFrameWithBubbleFrame:(CGRect)bubbleFrame {
CGRect voiceUnreadDotFrame = _voiceUnreadDotImageView.frame;
voiceUnreadDotFrame.origin.x = (self.message.bubbleMessageType == XHBubbleMessageTypeSending ? self.bubbleImageView.frame.origin.x - kXHUnReadDotSize * 3 : CGRectGetMaxX(self.bubbleImageView.frame))+kXHUnReadDotSize;
voiceUnreadDotFrame.origin.y = self.bubbleImageView.frame.origin.y + kXHUnReadDotSize / 2.0;
// voiceUnreadDotFrame.origin.y = CGRectGetMidY(bubbleFrame) - kXHUnReadDotSize / 2.0;
_voiceUnreadDotImageView.frame = voiceUnreadDotFrame;
}
- (void)configureStatuesImageViewFrameWithBubbleFrame:(CGRect)bubbleFrame {
if ([[self.message status] isEqualToNumber:@1] && self.message.bubbleMessageType == XHBubbleMessageTypeSending) {
CGRect statuesFrame = _statusImageView.frame;
statuesFrame.origin.x = (self.message.bubbleMessageType == XHBubbleMessageTypeSending ? bubbleFrame.origin.x - CGRectGetWidth(statuesFrame) - 5 : bubbleFrame.origin.x + bubbleFrame.size.width + 5);
statuesFrame.origin.y = CGRectGetMaxY(bubbleFrame) - CGRectGetHeight(statuesFrame);
_statusImageView.frame = statuesFrame;
_statusImageView.hidden = NO;
}else{
_statusImageView.hidden = YES;
}
}
#pragma mark - Life cycle
- (instancetype)initWithFrame:(CGRect)frame
message:(XHMessage *)message {
self = [super initWithFrame:frame];
if (self) {
// Initialization code
_message = message;
// 1、初始化气泡的背景
if (!_bubbleImageView) {
//bubble image
FLAnimatedImageView *bubbleImageView = [[FLAnimatedImageView alloc] init];
bubbleImageView.frame = self.bounds;
bubbleImageView.userInteractionEnabled = YES;
[self addSubview:bubbleImageView];
_bubbleImageView = bubbleImageView;
//_bubbleImageView.backgroundColor = UIColor.blueColor;
}
// 2、初始化显示文本消息的TextView
if (!_displayTextView) {
SETextView *displayTextView = [[SETextView alloc] initWithFrame:CGRectZero];
displayTextView.textColor = [UIColor colorWithWhite:0.143 alpha:1.000];
displayTextView.backgroundColor = [UIColor clearColor];
displayTextView.selectable = NO;
displayTextView.lineSpacing = kXHTextLineSpacing;
displayTextView.font = [[XHMessageBubbleView appearance] font];
displayTextView.showsEditingMenuAutomatically = NO;
displayTextView.highlighted = NO;
[self addSubview:displayTextView];
_displayTextView = displayTextView;
}
// 3、初始化显示图片的控件
if (!_bubblePhotoImageView) {
XHBubblePhotoImageView *bubblePhotoImageView = [[XHBubblePhotoImageView alloc] initWithFrame:CGRectZero];
[self addSubview:bubblePhotoImageView];
_bubblePhotoImageView = bubblePhotoImageView;
if (!_videoPlayImageView) {
UIImageView *videoPlayImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"MessageVideoPlay"]];
[bubblePhotoImageView addSubview:videoPlayImageView];
_videoPlayImageView = videoPlayImageView;
}
if (!_geolocationsLabel) {
UILabel *geolocationsLabel = [[UILabel alloc] initWithFrame:CGRectZero];
geolocationsLabel.numberOfLines = 0;
geolocationsLabel.lineBreakMode = NSLineBreakByTruncatingTail;
geolocationsLabel.textColor = [UIColor whiteColor];
geolocationsLabel.backgroundColor = [UIColor clearColor];
geolocationsLabel.font = [UIFont systemFontOfSize:12];
[bubblePhotoImageView addSubview:geolocationsLabel];
_geolocationsLabel = geolocationsLabel;
}
}
// 4、初始化显示语音时长的label
if (!_voiceDurationLabel) {
UILabel *voiceDurationLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 8, 28, 20)];
voiceDurationLabel.textColor = [UIColor colorWithWhite:0.579 alpha:1.000];
voiceDurationLabel.backgroundColor = [UIColor clearColor];
voiceDurationLabel.font = [UIFont systemFontOfSize:13.f];
voiceDurationLabel.textAlignment = NSTextAlignmentCenter;
voiceDurationLabel.hidden = YES;
[self addSubview:voiceDurationLabel];
_voiceDurationLabel = voiceDurationLabel;
}
// 5、初始化显示gif表情的控件
if (!_emotionImageView) {
FLAnimatedImageView *emotionImageView = [[FLAnimatedImageView alloc] initWithFrame:CGRectZero];
[self addSubview:emotionImageView];
_emotionImageView = emotionImageView;
}
// 6. 初始化显示语音未读标记的imageview
if (!_voiceUnreadDotImageView) {
NSString *voiceUnreadImageName = [[XHConfigurationHelper appearance].messageTableStyle objectForKey:kXHMessageTableVoiceUnreadImageNameKey];
if (!voiceUnreadImageName) {
voiceUnreadImageName = @"msg_chat_voice_unread";
}
UIImageView *voiceUnreadDotImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, kXHUnReadDotSize, kXHUnReadDotSize)];
voiceUnreadDotImageView.image = [UIImage imageNamed:voiceUnreadImageName];
voiceUnreadDotImageView.hidden = YES;
[self addSubview:voiceUnreadDotImageView];
_voiceUnreadDotImageView = voiceUnreadDotImageView;
}
if (!_statusImageView) {
UIImageView *statusImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 20, 20)];
statusImageView.image = [myHelper getImageWithName:@"chat_发送成功"];
[self addSubview:statusImageView];
_statusImageView = statusImageView;
}
}
return self;
}
- (void)dealloc {
_message = nil;
_displayTextView = nil;
_bubbleImageView = nil;
_bubblePhotoImageView = nil;
_animationVoiceImageView = nil;
_voiceUnreadDotImageView = nil;
_statusImageView = nil;
_voiceDurationLabel = nil;
_emotionImageView = nil;
_videoPlayImageView = nil;
_geolocationsLabel = nil;
_font = nil;
}
- (void)layoutSubviews {
[super layoutSubviews];
XHBubbleMessageMediaType currentType = self.message.messageMediaType;
switch (currentType) {
case XHBubbleMessageMediaTypeText:
case XHBubbleMessageMediaTypeVoice:
case XHBubbleMessageMediaTypeEmotion: {
// 获取实际气泡的大小
CGRect bubbleFrame = [self bubbleFrame];
self.bubbleImageView.frame = bubbleFrame;
if (currentType == XHBubbleMessageMediaTypeText) {
CGFloat textX = -(kXHArrowMarginWidth / 2.0);
if (self.message.bubbleMessageType == XHBubbleMessageTypeReceiving) {
textX = kXHArrowMarginWidth / 2.0;
}
CGRect displayTextViewFrame = CGRectZero;
displayTextViewFrame.size.width = CGRectGetWidth(bubbleFrame) - kXHLeftTextHorizontalBubblePadding - kXHRightTextHorizontalBubblePadding - kXHArrowMarginWidth;
displayTextViewFrame.size.height = CGRectGetHeight(bubbleFrame) - kXHHaveBubbleMargin * 2.8;
self.displayTextView.frame = displayTextViewFrame;
self.displayTextView.center = CGPointMake(self.bubbleImageView.center.x + textX, self.bubbleImageView.center.y);
}
if (currentType == XHBubbleMessageMediaTypeVoice) {
// 配置语音播放的位置
CGRect animationVoiceImageViewFrame = self.animationVoiceImageView.frame;
CGFloat voiceImagePaddingX = CGRectGetMaxX(bubbleFrame) - kXHVoiceMargin - CGRectGetWidth(animationVoiceImageViewFrame);
if (self.message.bubbleMessageType == XHBubbleMessageTypeReceiving) {
voiceImagePaddingX = CGRectGetMinX(bubbleFrame) + kXHVoiceMargin;
}
animationVoiceImageViewFrame.origin = CGPointMake(voiceImagePaddingX, CGRectGetMidY(bubbleFrame) - CGRectGetHeight(animationVoiceImageViewFrame) / 2.0); // 垂直居中
self.animationVoiceImageView.frame = animationVoiceImageViewFrame;
[self configureVoiceDurationLabelFrameWithBubbleFrame:bubbleFrame];
[self configureVoiceUnreadDotImageViewFrameWithBubbleFrame:bubbleFrame];
}
if (currentType == XHBubbleMessageMediaTypeEmotion) {
CGRect emotionImageViewFrame = bubbleFrame;
emotionImageViewFrame.size = [XHMessageBubbleView neededSizeForEmotion];
self.emotionImageView.frame = emotionImageViewFrame;
}
[self configureStatuesImageViewFrameWithBubbleFrame:bubbleFrame];
break;
}
case XHBubbleMessageMediaTypePhoto:
case XHBubbleMessageMediaTypeVideo:
case XHBubbleMessageMediaTypeLocalPosition: {
CGSize needPhotoSize = [XHMessageBubbleView neededSizeForPhoto:self.message.photo];
CGFloat paddingX = 0.0f;
if (self.message.bubbleMessageType == XHBubbleMessageTypeSending) {
paddingX = CGRectGetWidth(self.bounds) - needPhotoSize.width;
}
CGFloat marginY = kXHNoneBubblePhotoMargin;
if (currentType == XHBubbleMessageMediaTypePhoto || currentType == XHBubbleMessageMediaTypeLocalPosition) {
marginY = kXHHaveBubblePhotoMargin;
}
CGRect photoImageViewFrame = CGRectMake(paddingX, marginY, needPhotoSize.width, needPhotoSize.height);
self.bubblePhotoImageView.frame = photoImageViewFrame;
[self configureStatuesImageViewFrameWithBubbleFrame:photoImageViewFrame];
self.videoPlayImageView.center = CGPointMake(CGRectGetWidth(photoImageViewFrame) / 2.0, CGRectGetHeight(photoImageViewFrame) / 2.0);
CGRect geolocationsLabelFrame = CGRectMake(11, CGRectGetHeight(photoImageViewFrame) - 47, CGRectGetWidth(photoImageViewFrame) - 20, 40);
self.geolocationsLabel.frame = geolocationsLabelFrame;
break;
}
default:
break;
}
}
@end