效果:
====直接上代码吧===
//
// UILabel+StringFrame.h
// QYER
//
// Created by qyer on 15/3/19.
// Copyright (c) 2015年 QYER. All rights reserved.
//
#import <UIKit/UIKit.h>
/**
* uilable 行间距高度
*/
static CGFloat const lineSapceHeight = 5.0f;
@interface UILabel (StringFrame) #pragma mark - 获取UILable Size - (CGSize)boundingRectWithSize:(CGSize)size; /** * 根据文字长度计算大小 * * @param content 文字长度 * @param pFont 文字字号 * @param pWidth 宽度 * */ +(CGSize)getContentSize:(NSString *)content font:(UIFont *)pFont width:(CGFloat)pWidth; /** * 根据文字长度计算大小 * * @param content 文字长度 * @param pFont 文字字号 * @param pHeight 高度 * */ +(CGSize)getContentSize:(NSString *)content font:(UIFont *)pFont height:(CGFloat)pHeight; /** * 根据文本获取size ,有最大 宽高限制 * * @param string 文本 * @param maxWidth 最大宽 * @param maxHeight 最大高 * @param font 字体 * @param lineSpace 行间距(如果使用默认的,就传nil) * * @return size */ +(CGSize)getContentSizeWithContentText:(NSString *)string andMaxWidth:(CGFloat)maxWidth andMaxHeight:(CGFloat)maxHeight AndFont:(UIFont*)font andLineSpacing:(NSNumber *)lineSpace; /** * 根据文本获取size ,有最大 宽高限制 * * @param string 文本 * @param maxWidth 最大宽 * @param maxHeight 最大高 * @param attribute 富文本属性 * * @return size */ +(CGSize)getContentSizeWithContentText:(NSString *)string andMaxWidth:(CGFloat)maxWidth andMaxHeight:(CGFloat)maxHeight andAttributes:(NSDictionary *)attribute; #pragma mark - 获取UILable 每行显示的文字 /** * 获取lalbe 每行文字 * * @return 每行文字数组 */ - (NSArray *)getSeparatedLines; /** * 获取lalbe 每行文字 * * @param text 根据文字内容 * * @return 每行文字数组 */ - (NSArray *)getSeparatedLinesWithText:(NSString*)text; /** * 获取lalbe 每行文字 * * @param content 文字内容 * @param fonte fonte description * @param size size description * * @return return value description */ +(NSArray *)getSeparatedLinesWithText:(NSString*)content andFonte:(UIFont *)fonte andSize:(CGSize)size; #pragma mark - 完美解决 向UILable 文字最后插入N张图片,支持向限制行数的UILable 最后一行插入,多余文字显示... /** * 向文字末尾追加图片,适用于已知Size的UILable * * @param contentStr 文字内容 * @param imgs 插入的图片数组, 图片最好带间隔哦 */ -(void)insertImgToContentLast:(NSString *)contentStr imgs:(NSArray *)imgs; /** * 向文字末尾追加图片,适用于AutoLayout 的UILable * * @param contentStr 文字内容 * @param imgs 插入的图片数组, 图片最好带间隔哦 * @param estimateWidth 预估的UILable 最大宽度(已知的最大宽度) */ -(void)insertImgToContentLast:(NSString *)contentStr imgs:(NSArray *)imgs estimateWidth:(CGFloat)estimateWidth; /** * 向已知文字后插入图片 * * @param insertImgArr insertImgArr description * @param appendAttributedString 可为nil */ -(void)configTitleLableAttributedString:(NSArray *)insertImgArr AttributedString:(NSMutableAttributedString *)appendAttributedString; @end
//
// UILabel+StringFrame.m
// QYER
//
// Created by qyer on 15/3/19.
// Copyright (c) 2015年 QYER. All rights reserved.
//
#import "UILabel+StringFrame.h"
#import <CoreText/CoreText.h>
@implementation UILabel (StringFrame)
#pragma mark - 获取UILable Size
- (CGSize)boundingRectWithSize:(CGSize)size { NSDictionary *attribute = @{NSFontAttributeName: self.font}; CGSize retSize = [self.text boundingRectWithSize:size options:\ NSStringDrawingTruncatesLastVisibleLine | NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading attributes:attribute context:nil].size; return retSize; } +(CGSize)getContentSize:(NSString *)content font:(UIFont *)pFont width:(CGFloat)pWidth{ CGSize contentSize; if (ios7) { contentSize = [content boundingRectWithSize:CGSizeMake(pWidth, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:[NSDictionary dictionaryWithObjectsAndKeys:pFont,NSFontAttributeName, nil] context:nil].size; }else{ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" contentSize = [content sizeWithFont:pFont constrainedToSize:CGSizeMake(pWidth, MAXFLOAT) lineBreakMode:NSLineBreakByCharWrapping]; #pragma clang diagnostic pop } return contentSize; } +(CGSize)getContentSize:(NSString *)content font:(UIFont *)pFont height:(CGFloat)pHeight{ CGSize contentSize; if (ios7) { contentSize = [content boundingRectWithSize:CGSizeMake(MAXFLOAT, pHeight) options:NSStringDrawingUsesLineFragmentOrigin attributes:[NSDictionary dictionaryWithObjectsAndKeys:pFont,NSFontAttributeName, nil] context:nil].size; }else{ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" contentSize = [content sizeWithFont:pFont constrainedToSize:CGSizeMake(MAXFLOAT, pHeight) lineBreakMode:NSLineBreakByCharWrapping]; #pragma clang diagnostic pop } return contentSize; } /** * 根据文本获取size ,有最大 宽高限制 * * @param string 文本 * @param maxWidth 最大宽 * @param maxHeight 最大高 * @param attribute 富文本属性 * * @return size */ +(CGSize)getContentSizeWithContentText:(NSString *)string andMaxWidth:(CGFloat)maxWidth andMaxHeight:(CGFloat)maxHeight andAttributes:(NSDictionary *)attribute{ CGSize size = CGSizeZero; if (IsEmpty(string)) { return size; } if (string) { if ([string respondsToSelector: @selector(boundingRectWithSize:options:attributes:context:)]) { size = [string boundingRectWithSize:CGSizeMake(maxWidth, maxHeight) options:NSStringDrawingUsesLineFragmentOrigin| NSStringDrawingTruncatesLastVisibleLine |NSStringDrawingUsesFontLeading attributes:attribute context:nil].size; }else { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" size = [string sizeWithFont:attribute[@"NSFontAttributeName"] constrainedToSize:CGSizeMake(maxWidth, maxHeight) lineBreakMode:NSLineBreakByCharWrapping]; #pragma clang diagnostic pop } } if (!CGSizeEqualToSize(CGSizeZero, size)) { CGFloat wight = maxWidth; CGFloat height = ceil(size.height); /** * 使用 NIAttributedLabel 有个bug ,当文字只有一行或不满一行 会出现文字显示不出来 */ if (!attribute) { NSArray *rows = [UILabel getSeparatedLinesWithText:string andFonte:attribute[NSFontAttributeName] andSize:size]; if ([rows count]==1) { CGSize offsetSize = [UILabel getContentSize:string font:attribute[NSFontAttributeName] width:maxWidth]; size = CGSizeMake(ceil(offsetSize.width) , ceil(offsetSize.height)); }else{ size = CGSizeMake(wight ,height); } }else { size = CGSizeMake(wight ,height); } } return size; } /** * 根据文本获取size ,有最大 宽高限制 * * @param string 文本 * @param maxWidth 最大宽 * @param maxHeight 最大高 * @param font 字体 * @param lineSpace 行间距(如果使用默认的,就传nil) * * @return size */ +(CGSize)getContentSizeWithContentText:(NSString *)string andMaxWidth:(CGFloat)maxWidth andMaxHeight:(CGFloat)maxHeight AndFont:(UIFont*)font andLineSpacing:(NSNumber *)lineSpace{ CGSize size = CGSizeZero; if (IsEmpty(string)) { return size; } if (string && font) { if ([string respondsToSelector: @selector(boundingRectWithSize:options:attributes:context:)]) { NSMutableParagraphStyle * paragraphStyle = [[NSMutableParagraphStyle alloc] init]; paragraphStyle.lineBreakMode = NSLineBreakByWordWrapping; paragraphStyle.alignment = NSTextAlignmentLeft; if (lineSpace) { paragraphStyle.lineSpacing = [lineSpace floatValue]; } size = [string boundingRectWithSize:CGSizeMake(maxWidth, maxHeight) options:NSStringDrawingUsesLineFragmentOrigin| NSStringDrawingTruncatesLastVisibleLine |NSStringDrawingUsesFontLeading attributes:@{NSFontAttributeName:font, NSParagraphStyleAttributeName:paragraphStyle} context:nil].size; }else { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" size = [string sizeWithFont:font constrainedToSize:CGSizeMake(maxWidth, maxHeight) lineBreakMode:NSLineBreakByCharWrapping]; #pragma clang diagnostic pop } } if (!CGSizeEqualToSize(CGSizeZero, size)) { CGFloat wight = ceil(maxWidth); CGFloat height = ceil(size.height ); /** * 使用 NIAttributedLabel 有个bug ,当文字只有一行或不满一行 会出现文字显示不出来 */ NSArray *rows = [UILabel getSeparatedLinesWithText:string andFonte:font andSize:size]; if ([rows count]==1) { CGSize offsetSize = [UILabel getContentSize:string font:font width:maxWidth]; size = CGSizeMake(ceil(offsetSize.width) , ceil(offsetSize.height)); }else{ size = CGSizeMake(wight ,height); } } return size; } #pragma mark - 获取UILable 每行显示的文字 /** * 获取lalbe 每行文字 * * @return 每行文字数组 */ - (NSArray *)getSeparatedLines { return [self getSeparatedLinesWithText:self.text]; } /** * 获取lalbe 每行文字 * * @param text 根据文字内容 * * @return 每行文字数组 */ - (NSArray *)getSeparatedLinesWithText:(NSString*)text { /** * fix NSConcreteMutableAttributedString initWithString:: nil value */ if (!(text && [text isKindOfClass:[NSString class]])) { return nil; } return [UILabel getSeparatedLinesWithText:text andFonte:[self font] andSize:[self frame].size]; } /** * 获取lalbe 每行文字 * * @param content 文字内容 * @param fonte fonte description * @param size size description * * @return 每行文字数组 */ +(NSArray *)getSeparatedLinesWithText:(NSString*)content andFonte:(UIFont *)fonte andSize:(CGSize)size{ if (!(content&&[content isKindOfClass:[NSString class]]) || !(fonte&& [fonte isKindOfClass:[UIFont class]]) || CGSizeEqualToSize(CGSizeZero, size)) { return nil; } NSString *text = content; UIFont *font = fonte; CGRect rect = CGRectMake(0, 0, size.width,size.height); CTFontRef myFont = CTFontCreateWithName((__bridge CFStringRef)([font fontName]), [font pointSize], NULL); NSMutableAttributedString *attStr = [[NSMutableAttributedString alloc] initWithString:text]; [attStr addAttribute:(NSString *)kCTFontAttributeName value:(__bridge id)myFont range:NSMakeRange(0, attStr.length)]; CTFramesetterRef frameSetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)attStr); CGMutablePathRef path = CGPathCreateMutable(); CGPathAddRect(path, NULL, CGRectMake(0,0,rect.size.width,100000)); CTFrameRef frame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, 0), path, NULL); NSArray *lines = (__bridge NSArray *)CTFrameGetLines(frame); NSMutableArray *linesArray = [[NSMutableArray alloc]init]; for (id line in lines) { CTLineRef lineRef = (__bridge CTLineRef )line; CFRange lineRange = CTLineGetStringRange(lineRef); NSRange range = NSMakeRange(lineRange.location, lineRange.length); NSString *lineString = [text substringWithRange:range]; [linesArray addObject:lineString]; } CFRelease(frameSetter); CFRelease(myFont); CFRelease(frame); CFRelease(path); return (NSArray *)linesArray; } #pragma mark - 完美解决 向UILable 文字最后插入N张图片,支持向限制行数的UILable 最后一行插入,多余文字显示... /** * 向文字末尾追加图片,适用于已知Size的UILable * * @param contentStr 文字内容 * @param imgs 插入的图片数组, 图片最好带间隔哦 */ -(void)insertImgToContentLast:(NSString *)contentStr imgs:(NSArray *)imgs{ if (IsEmpty(contentStr) || !imgs || [imgs count] == 0) { self.text = IsEmpty(contentStr)?@"":contentStr; return ; } [self insertImgToContentLast:contentStr imgs:imgs estimateWidth:[self frame].size.width]; } /** * 向文字末尾追加图片,适用于AutoLayout 的UILable * * @param contentStr 文字内容 * @param imgs 插入的图片数组, 图片最好带间隔哦 * @param estimateWidth 预估的UILable 最大宽度(已知的最大宽度) */ -(void)insertImgToContentLast:(NSString *)contentStr imgs:(NSArray *)imgs estimateWidth:(CGFloat)estimateWidth{ if (IsEmpty(contentStr) || !imgs || [imgs count] == 0 || estimateWidth == 0) { self.text = IsEmpty(contentStr)?@"":contentStr; return ; } //获取每行文字需要预设宽度,不然每个字都会是单独的一行 self.width = estimateWidth; NSArray *textLineArr = [self getSeparatedLinesWithText:contentStr]; NSInteger maxLine = self.numberOfLines; if (maxLine == 0) { self.text = contentStr; //追加图片 [self configTitleLableAttributedString:imgs AttributedString:nil]; return; } NSInteger lastLineIndex = maxLine - 1; if ([textLineArr count] <= lastLineIndex) { self.text = contentStr; //追加图片 [self configTitleLableAttributedString:imgs AttributedString:nil]; return; } __block CGFloat imgWith = 0.0; [imgs enumerateObjectsUsingBlock:^(UIImage* img, NSUInteger idx, BOOL * _Nonnull stop) { imgWith += img.size.width; }]; CGFloat lastTextMaxWith = estimateWidth - imgWith; if (lastTextMaxWith <= 0) { self.text = contentStr; //追加图片 [self configTitleLableAttributedString:imgs AttributedString:nil]; return ; } if ([textLineArr count] > lastLineIndex) { NSMutableString *muShowTitle = [NSMutableString string]; [textLineArr enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { if (idx > (lastLineIndex - 1)) { //预设宽度 self.width = lastTextMaxWith; //最大宽带下能显示的字数 NSArray *lastLineArr = [self getSeparatedLinesWithText:textLineArr[lastLineIndex]]; NSString *lastLineText = lastLineArr[0]; // DDLogDebug(@"====lastLineText=======%@==",lastLineText); if ([lastLineArr count] > 1) { lastLineText = [lastLineText stringByReplacingCharactersInRange:NSMakeRange(lastLineText.length - 3, 3) withString:@"..."]; } // DDLogDebug(@"====lastLineArr[0]=======%@==",lastLineText); [muShowTitle appendString:lastLineText]; * stop = YES; return ; } [muShowTitle appendString:textLineArr[idx]]; }]; self.text = muShowTitle; // self.width = estimateWidth; } //追加图片 [self configTitleLableAttributedString:imgs AttributedString:nil]; } /** * 向已知文字后插入图片 * * @param insertImgArr insertImgArr description * @param appendAttributedString 可为nil */ -(void)configTitleLableAttributedString:(NSArray *)insertImgArr AttributedString:(NSMutableAttributedString *)appendAttributedString{ if (!insertImgArr || [insertImgArr count] == 0) { return ; } if (!appendAttributedString) { appendAttributedString = [[NSMutableAttributedString alloc] initWithString:self.text]; } [insertImgArr enumerateObjectsUsingBlock:^(UIImage* img, NSUInteger idx, BOOL * _Nonnull stop) { NSTextAttachment *textAttachment = [[NSTextAttachment alloc] init]; //带 x 的 textAttachment.image = img; CGFloat mid = self.font.descender + self.font.capHeight; CGFloat imgY = self.font.descender - textAttachment.image.size.height/2 + mid + 2; textAttachment.bounds = CGRectMake(0, imgY, textAttachment.image.size.width, textAttachment.image.size.height); NSAttributedString *iconAttributedString = [NSAttributedString attributedStringWithAttachment:textAttachment]; [appendAttributedString replaceCharactersInRange:NSMakeRange(self.text.length, 0) withAttributedString:iconAttributedString]; /** fix,当文字刚好够一行,添加图片后折行,but.第二行图片和第一行文字没有行间距。。 http://scottzhu.com/blog/2015/02/14/attach-stars-to-the-end-of-a-uilabel/ */ [appendAttributedString appendAttributedString: [[NSAttributedString alloc] initWithString:@" "]]; }]; self.attributedText = appendAttributedString; } @end