// TTSingleLineView.h #import <UIKit/UIKit.h> #import "TTLineView.h" #define kChatRoomSingleLineSendFontSize (18.0f) @interface TTSingleLineView : TTLineView + (TTSingleLineView *)singleLineView:(NSArray *)views; @end //TTSingleLineView.m #import "TTSingleLineView.h" #define kChatRoomSingleLineDefaultHeight (30.0f) @implementation TTSingleLineView - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { // Initialization code // self.backgroundColor = [UIColor colorWithWhite:0.4f alpha:0.4f]; } return self; } + (TTSingleLineView *)singleLineView:(NSArray *)views { TTSingleLineView *slv = [[TTSingleLineView alloc] initWithFrame:CGRectZero]; [slv chatRoomSingleLineView:views]; return slv; } - (CGFloat)chatRoomSingleLineView:(NSArray *)array { CGFloat lineWidth = 0.0f; for (NSDictionary *dict in array) { switch ([self contentType:dict]) { case kChatRoomText: { NSString *contentText = [self chatContentText:dict]; CGFloat fontSize = [self chatContentTextFont:dict]; CGFloat textWidth = [self getStringWidth:contentText size:fontSize]; ChatRoomFontColorMode colorMode = [[dict valueForKey:kChatTextColorTypeKeyName] integerValue]; UIColor *color = [self chatTextColor:colorMode]; UILabel *l = [[UILabel alloc] initWithFrame:CGRectMake(lineWidth, 0.0f, textWidth, kChatRoomSingleLineDefaultHeight)]; l.backgroundColor = [UIColor clearColor]; l.font = kFontOfSize(fontSize); l.text = contentText; l.textColor = color; l.lineBreakMode = NSLineBreakByCharWrapping; [self addSubview:l]; lineWidth += textWidth; } break; case kChatRoomRemoteDynamicImage: case kChatRoomRemoteStaticImage: { NSString *imageStr = [self chatImagePath:dict]; CGFloat imageWidth = [self chatImageWidth:dict]; CGFloat imageHeight = [self chatImageHeight:dict]; CGFloat imagePaddingX = [self chatImagePaddingX:dict]; CGFloat imagePaddingY = [self chatImagePaddingY:dict]; imageStr = [imageStr substringFromIndex:kChatCutOffContentRemoteStillImageType.length]; UIImageView *imageView = [[UIImageView alloc] initWithFrame: CGRectMake(lineWidth + imagePaddingX, 0.0f + imagePaddingY, imageWidth, imageHeight)]; [imageView setImageWithURL:[NSURL URLWithString:imageStr] placeholderImage:nil]; [self addSubview:imageView]; lineWidth += imageWidth; lineWidth += imagePaddingX; } break; case kChatRoomLocalDynamicImage: case kChatRoomLocalStaticImage: { NSString *imageStr = [self chatImagePath:dict]; CGFloat imageWidth = [self chatImageWidth:dict]; CGFloat imageHeight = [self chatImageHeight:dict]; CGFloat imagePaddingX = [self chatImagePaddingX:dict]; CGFloat imagePaddingY = [self chatImagePaddingY:dict]; imageStr = [imageStr substringFromIndex:kChatCutOffContentRemoteStillImageType.length]; UIImageView *imageView = [[UIImageView alloc] initWithFrame: CGRectMake(lineWidth + imagePaddingX, 0.0f + imagePaddingY, imageWidth, imageHeight)]; imageView.image = kImageNamed(imageStr); [self addSubview:imageView]; lineWidth += imageWidth; lineWidth += imagePaddingX; } break; default: break; } } self.frame = CGRectMake(0.0f, 0.0f, lineWidth, kChatRoomSingleLineDefaultHeight); return kChatRoomSingleLineDefaultHeight; } - (CGFloat)getStringWidth:(NSString *)text size:(CGFloat)fontSize { CGSize size = [text sizeWithFont:kFontOfSize(fontSize) constrainedToSize:CGSizeMake(MAXFLOAT, kChatRoomSingleLineDefaultHeight)]; return size.width; } /* // Only override drawRect: if you perform custom drawing. // An empty implementation adversely affects performance during animation. - (void)drawRect:(CGRect)rect { // Drawing code } */ @end // TTMultiLineView.h #import <UIKit/UIKit.h> #import "TTLineView.h" @interface TTMultiLineView : TTLineView @property (nonatomic, assign) CGFloat previousHeight; // View's total height. @property (nonatomic, assign) CGFloat height; @property (nonatomic, assign) CGFloat padding; + (TTMultiLineView *)multiLineView:(NSArray *)views; @end // TTMultiLineView.m #import "TTMultiLineView.h" #define kChatTextHeightDefault (24.0f) #define kChatViewWidthMax (kScreenWidth - self.padding * 2) #define kChatSplitSingleWordWidth (15.0f) #define kChatContentPadding (0.0f) // Parse. #define kChatParseTextWidthKeyName @"chat.parse.text.width" #define kChatParseTextContentKeyName @"chat.parse.text.content" #define kChatParseTextCutPointKeyName @"chat.parse.text.cutpoint" @implementation TTMultiLineView - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { // Initialization code } return self; } + (TTMultiLineView *)multiLineView:(NSArray *)views { TTMultiLineView *mlv = [[TTMultiLineView alloc] initWithFrame:CGRectZero]; [mlv chatMultiLineView:views]; return mlv; } - (CGFloat)chatMultiLineView:(NSArray *)array { CGFloat viewWidth = 0.0f; CGFloat viewHeightMax = 0.0f; if (self.padding == 0.0f) { self.padding = kChatContentPadding; } for (NSDictionary *dict in array) { switch ([self contentType:dict]) { case kChatRoomText: { NSString *contentText = [self chatContentText:dict]; CGFloat fontSize = [self chatContentTextFont:dict]; if (contentText != nil && contentText.length > 0) { CGSize firstCharSize = [[contentText substringToIndex:1] sizeWithFont:kFontOfSize(fontSize) constrainedToSize:CGSizeMake(MAXFLOAT, kChatTextHeightDefault)]; if (viewWidth + firstCharSize.width > kChatViewWidthMax) { // insert new line if last string reach end. self.previousHeight += kChatTextHeightDefault; viewWidth = 0.0f; } } NSArray *sectionStrs = [self splitString:contentText start:viewWidth size:fontSize]; // Multiline. NSUInteger line = 0; for (NSDictionary *d in sectionStrs) { NSUInteger width = [[d valueForKey:kChatParseTextWidthKeyName] unsignedIntegerValue]; NSString *text = [d valueForKey:kChatParseTextContentKeyName]; ChatRoomFontColorMode colorMode = [[dict valueForKey:kChatTextColorTypeKeyName] integerValue]; UIColor *color = [self chatTextColor:colorMode]; if (line != 0) { viewWidth = 0.0f; if (line == 1) { // First Line self.previousHeight += MAX(kChatTextHeightDefault, viewHeightMax); viewHeightMax = kChatTextHeightDefault; } else { // > 1 line. self.previousHeight += kChatTextHeightDefault; } } else { viewHeightMax = MAX(viewHeightMax, kChatTextHeightDefault); } UILabel *l = [[UILabel alloc] initWithFrame:CGRectMake(viewWidth, self.previousHeight, width, kChatTextHeightDefault)]; l.backgroundColor = [UIColor clearColor]; l.font = kFontOfSize(fontSize); l.text = text; l.textColor = color; l.lineBreakMode = NSLineBreakByCharWrapping; // l.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleBottomMargin; [self addSubview:l]; if (line == [sectionStrs count] - 1) { // Last Line, recode width. viewWidth += width; } line++; } } break; case kChatRoomRemoteDynamicImage: case kChatRoomLocalDynamicImage: { NSString *imageStr = [self chatImagePath:dict]; CGFloat imageWidth = [self chatImageWidth:dict]; CGFloat imageHeight = [self chatImageHeight:dict]; CGFloat imagePaddingX = [self chatImagePaddingX:dict]; CGFloat imagePaddingY = [self chatImagePaddingY:dict]; if (viewWidth + imageWidth > kChatViewWidthMax) { // new line self.previousHeight += viewHeightMax; viewHeightMax = MAX(viewHeightMax, imageHeight); viewWidth = 0.0f; } imageStr = [imageStr substringFromIndex:kChatCutOffContentLocalDynamicImageType.length]; // LOGINFO(@"imageStr = %@", imageStr); UIImageView *imageView = [[UIImageView alloc] initWithFrame: CGRectMake(viewWidth + imagePaddingX, self.previousHeight + imagePaddingY, imageWidth, imageHeight)]; imageView.image = [UIImage sd_animatedGIFNamed:imageStr]; [self addSubview:imageView]; viewWidth += imageWidth; viewWidth += imagePaddingX; viewHeightMax = MAX(imageHeight, viewHeightMax); } break; case kChatRoomLocalStaticImage: case kChatRoomRemoteStaticImage: { NSString *imageStr = [self chatImagePath:dict]; CGFloat imageWidth = [self chatImageWidth:dict]; CGFloat imageHeight = [self chatImageHeight:dict]; CGFloat imagePaddingX = [self chatImagePaddingX:dict]; CGFloat imagePaddingY = [self chatImagePaddingY:dict]; // LOGINFO(@"imageStr = %@", imageStr); if (viewWidth + imageWidth > kChatViewWidthMax) { // new line self.previousHeight += viewHeightMax; viewHeightMax = MAX(viewHeightMax, imageHeight); viewWidth = 0.0f; } imageStr = [imageStr substringFromIndex:kChatCutOffContentRemoteStillImageType.length]; UIImageView *imageView = [[UIImageView alloc] initWithFrame: CGRectMake(viewWidth + imagePaddingX, self.previousHeight + imagePaddingY, imageWidth, imageHeight)]; [imageView setImageWithURL:[NSURL URLWithString:imageStr] placeholderImage:nil]; [self addSubview:imageView]; viewWidth += imageWidth; viewWidth += imagePaddingX; viewHeightMax = MAX(imageHeight, viewHeightMax); } break; default: break; } } CGFloat totalHeight = self.previousHeight + viewHeightMax; if (totalHeight == 0.0f) { // Text Single Line; totalHeight = kChatTextHeightDefault; } self.frame = CGRectMake(self.padding, 0.0f, kChatViewWidthMax, totalHeight); return totalHeight; } - (NSArray *)splitString:(NSString *)str start:(CGFloat)loc size:(CGFloat)fontSize { NSMutableArray *array = [NSMutableArray arrayWithCapacity:0]; NSUInteger i = 1; NSUInteger location = 0; NSUInteger startPoint = 0; CGFloat startPaddingX = loc; // LOGINFO(@"str = %@ padding = %.2f", str, x); while (i < str.length) { NSRange range = NSMakeRange(location, i - startPoint); NSString *str1 = [str substringWithRange:range]; CGSize size = [str1 sizeWithFont:kFontOfSize(fontSize) constrainedToSize:CGSizeMake(MAXFLOAT, kChatTextHeightDefault)]; // LOGINFO(@"str1 = %@ size.width = %.2f", str1, size.width); if (size.width + startPaddingX + kChatSplitSingleWordWidth > kChatViewWidthMax) { startPaddingX = 0.0f; location += str1.length; startPoint = i; NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithCapacity:0]; [dictionary setValue:@(size.width) forKey:kChatParseTextWidthKeyName]; [dictionary setValue:str1 forKey:kChatParseTextContentKeyName]; [dictionary setValue:@(i) forKey:kChatParseTextCutPointKeyName]; [array addObject:dictionary]; } i++; } // Last Section String. NSString *lastSectionStr = [str substringFromIndex:location]; CGSize lastStrSize = [lastSectionStr sizeWithFont:kFontOfSize(fontSize) constrainedToSize:CGSizeMake(MAXFLOAT, kChatTextHeightDefault)]; NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithCapacity:0]; [dictionary setValue:@(lastStrSize.width) forKey:kChatParseTextWidthKeyName]; [dictionary setValue:lastSectionStr forKey:kChatParseTextContentKeyName]; [dictionary setValue:@(i) forKey:kChatParseTextCutPointKeyName]; [array addObject:dictionary]; return array; } /* // Only override drawRect: if you perform custom drawing. // An empty implementation adversely affects performance during animation. - (void)drawRect:(CGRect)rect { // Drawing code } */ @end