iOS Context 基础教程 (三)完整实现UILabel末尾 实现『省略号常看全文』显示
2017-08-02 14:55
1781 查看
直接上代码,实现限制UIlabel最多显示行数,超出后显示 『。。。全文』效果实现:
细节还待优化,给需要的人参考吧
BDHKLabelAttribute.h// BDHKLabelAttribute.h #import <UIKit/UIKit.h> /*! @enum BDHKVerticalTextAlignment @abstract 垂直方式 */ typedef NS_ENUM(NSInteger, BDHKVerticalTextAlignment) { /*! @abstract 顶部 */ BDHKVerticalTextAlignmentTop, /*! @abstract 居中 */ BDHKVerticalTextAlignmentMiddle, /*! @abstract 底部 */ BDHKVerticalTextAlignmentBottom }; @interface BDHKLabelAttribute : UILabel /*! @property verticalTextAlignment @abstract 上下对齐方式 */ @property (nonatomic, assign) BDHKVerticalTextAlignment verticalTextAlignment; /*! @property linesSpace @abstract 行间距 */ @property (nonatomic, assign) CGFloat linesSpace; /*! @property margin @abstract 边距 */ @property (nonatomic, assign) UIEdgeInsets margin; /*! @property lastLineRightIndent @abstract 尾行右缩进 */ //@property (nonatomic, assign) CGFloat lastLineRightIndent; /*! @property truncationEndAttributedString @abstract 尾行结束字符串 */ @property (nonatomic, strong) NSAttributedString *truncationEndAttributedString; /*! @property linesSpace @abstract 实际绘制的行数,当numberOfLines==0时 */ @property (nonatomic, assign, readonly) NSInteger drawOfLines; @end @interface NSString(BDHKLabelAttribute) /*! @method sizeWithFont:width:linesSpace:numberOfLines: @abstract 测量字符串所要的大小 @param font 字体 @param width 宽度 @param linesSpace 行高 @param numberOfLines 行数 */ - (CGSize)sizeWithFont:(UIFont *)font width:(CGFloat)width linesSpace:(CGFloat)linesSpace numberOfLines:(NSInteger)numberOfLines; @end
BDHKLabelAttribute.m
// BDHKLabelAttribute.m #import "BDHKLabelAttribute.h" #import "UIView+BDHKUtil.h" #import <CoreText/CoreText.h> @interface BDHKLabelAttribute() @property (nonatomic, copy) NSMutableAttributedString *attributedString; @property (nonatomic, assign) BOOL isDisplay; @property (nonatomic, assign) BOOL isText; @end @implementation BDHKLabelAttribute - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { _margin = UIEdgeInsetsZero; _verticalTextAlignment = BDHKVerticalTextAlignmentTop; _isDisplay = YES; } return self; } - (id)initWithCoder:(NSCoder *)aDecoder { self = [super initWithCoder:aDecoder]; if (self) { _margin = UIEdgeInsetsZero; _verticalTextAlignment = BDHKVerticalTextAlignmentTop; _isDisplay = YES; } return self; } -(void)dealloc { _attributedString = nil; _truncationEndAttributedString = nil; } - (void)drawTextInRect:(CGRect)rect { if (self.text.length == 0 && self.attributedText == nil) { return; } if (_isDisplay) { if (_isText) { self.attributedString = [self attributedStringAddStyle:self.text]; } else { self.attributedString = [[NSMutableAttributedString alloc] initWithAttributedString:self.attributedText]; } _isDisplay = NO; } if (!_attributedString) { return; } CGRect drawRect = CGRectMake(_margin.left, _margin.top, self.bounds.size.width - _margin.left - _margin.right, self.bounds.size.height - _margin.top - _margin.bottom); CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)_attributedString); CGMutablePathRef forecastPath = CGPathCreateMutable(); //CGPathAddRect(forecastPath, NULL ,self.bounds); CGPathAddRect(forecastPath, NULL ,drawRect); CTFrameRef forecastFrame = CTFramesetterCreateFrame(framesetter,CFRangeMake(0, 0), forecastPath , NULL); CFArrayRef forecastLines = CTFrameGetLines(forecastFrame); long forecastMaxLineNumber = (long)CFArrayGetCount(forecastLines); //CGRect drawingRect = CGRectMake(0, 0, self.bounds.size.width, CGFLOAT_MAX); CGRect drawingRect = CGRectMake(drawRect.origin.x, drawRect.origin.y, drawRect.size.width, 100000000); CGMutablePathRef textpath = CGPathCreateMutable(); CGPathAddRect(textpath, NULL, drawingRect); CTFrameRef textFrame = CTFramesetterCreateFrame(framesetter,CFRangeMake(0,0), textpath, NULL); CFArrayRef textlines = CTFrameGetLines(textFrame); long textMaxLineNumber = (long)CFArrayGetCount(textlines); long minLinesNumber = MIN(forecastMaxLineNumber, textMaxLineNumber); _drawOfLines = (int)(self.numberOfLines == 0 ? minLinesNumber : MIN(minLinesNumber, self.numberOfLines)); CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetTextMatrix(context , CGAffineTransformIdentity); CGContextTranslateCTM(context , 0 ,self.bounds.size.height); CGContextScaleCTM(context, 1.0 ,-1.0); CGPoint lineOrigins[_drawOfLines]; CTFrameGetLineOrigins(forecastFrame,CFRangeMake(0,_drawOfLines), lineOrigins); for(int lineIndex = 0;lineIndex < _drawOfLines;lineIndex++) { CTLineRef line = CFArrayGetValueAtIndex(forecastLines,lineIndex); CGPoint lineOrigin; if (forecastMaxLineNumber >= _drawOfLines && _verticalTextAlignment != BDHKVerticalTextAlignmentTop) { if (_verticalTextAlignment == BDHKVerticalTextAlignmentMiddle) { float topMargin = lineOrigins[_drawOfLines - 1].y / 2.0; lineOrigin = lineOrigins[lineIndex]; lineOrigin = CGPointMake(lineOrigin.x,lineOrigin.y - floorf(topMargin)); } else if(_verticalTextAlignment == BDHKVerticalTextAlignmentBottom){ CGFloat ascent; CGFloat descent; CGFloat leading; CTLineGetTypographicBounds(line, &ascent, &descent, &leading); lineOrigin = lineOrigins[_drawOfLines - 1 - lineIndex]; lineOrigin = CGPointMake(lineOrigin.x, (self.height - floorf(lineOrigin.y + ascent - descent))); } } else { lineOrigin = lineOrigins[lineIndex]; } CTLineRef lastLine = nil; if (_drawOfLines < textMaxLineNumber) { if (lineIndex == _drawOfLines - 1) { CFRange range = CTLineGetStringRange(line); NSDictionary *attributes = [_attributedString attributesAtIndex:range.location + range.length - 1 effectiveRange:NULL]; NSAttributedString *token = [[NSAttributedString alloc] initWithString:@"\u2026" attributes:attributes]; if (_truncationEndAttributedString != nil) { NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithAttributedString:token]; [attributedString appendAttributedString:_truncationEndAttributedString]; token = attributedString; } CFAttributedStringRef tokenRef = (__bridge CFAttributedStringRef)token; CTLineRef truncationToken = CTLineCreateWithAttributedString(tokenRef); NSRange lastLineRange = NSMakeRange(range.location, 0); lastLineRange.length = [_attributedString length] - lastLineRange.location; CFAttributedStringRef longString = (__bridge CFAttributedStringRef)[_attributedString attributedSubstringFromRange:lastLineRange]; CTLineRef endLine = CTLineCreateWithAttributedString(longString); //lastLine = CTLineCreateTruncatedLine(endLine, self.width - _lastLineRightIndent, kCTLineTruncationEnd, truncationToken); lastLine = CTLineCreateTruncatedLine(endLine, self.width, kCTLineTruncationEnd, truncationToken); if (truncationToken) { CFRelease(truncationToken); } if (endLine) { CFRelease(endLine); } } } if (lastLine) { CGContextSetTextPosition(context,lineOrigin.x,lineOrigin.y); CTLineDraw(lastLine,context); //从一行中得到CTRun数组,最后一个字的位置 //CFArrayRef runs = CTLineGetGlyphRuns(lastLine); //long runCount = (long)CFArrayGetCount(runs); //CTLineGetOffsetForStringIndex(line, runCount - 1, NULL); CFRelease(lastLine); } else { CGContextSetTextPosition(context,lineOrigin.x,lineOrigin.y); CTLineDraw(line,context); } } UIGraphicsPushContext(context); CFRelease(textpath); CFRelease(textFrame); CFRelease(forecastFrame); CFRelease(forecastPath); CFRelease(framesetter); } #pragma mark -- - (NSMutableAttributedString *)attributedStringAddStyle:(NSString *)string { if (!string) { return nil; } NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init]; style.lineSpacing = (_linesSpace > 0) ? _linesSpace : 4 ; style.paragraphSpacing = 0; style.alignment = self.textAlignment; NSMutableAttributedString *attributedString =[[NSMutableAttributedString alloc]initWithString:string]; NSDictionary *attributes = @{NSForegroundColorAttributeName:self.textColor,NSFontAttributeName:self.font,NSParagraphStyleAttributeName:style}; [attributedString addAttributes:attributes range:NSMakeRange(0, [attributedString length])]; return attributedString; } #pragma mark -- - (void)setText:(NSString *)text { self.isDisplay = YES; self.isText = YES; [super setText:text]; } - (void)setAttributedText:(NSAttributedString *)attributedText { self.isDisplay = YES; self.isText = NO; [super setAttributedText:attributedText]; } - (void)setTextColor:(UIColor *)textColor { self.isDisplay = YES; [super setTextColor:textColor]; } -(void)setTextAlignment:(NSTextAlignment)textAlignment { self.isDisplay = YES; [super setTextAlignment:textAlignment]; } -(void)setFont:(UIFont *)font { self.isDisplay = YES; [super setFont:font]; } -(void)setLinesSpace:(CGFloat)linesSpace { self.isDisplay = YES; _linesSpace = linesSpace; [self setNeedsDisplay]; } -(void)setVerticalTextAlignment:(BDHKVerticalTextAlignment)verticalTextAlignment { _verticalTextAlignment = verticalTextAlignment; [self setNeedsDisplay]; } -(void)setMargin:(UIEdgeInsets)margin { _margin = margin; [self setNeedsDisplay]; } @end @implementation NSString(BDHKLabelAttribute) - (CGSize)sizeWithFont:(UIFont *)font width:(CGFloat)width linesSpace:(CGFloat)linesSpace numberOfLines:(NSInteger)numberOfLines { if (self.length <= 0) { return CGSizeZero; } NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init]; style.lineSpacing = linesSpace ; style.paragraphSpacing = 0; NSMutableAttributedString *attributedString =[[NSMutableAttributedString alloc] initWithString:self]; NSDictionary *attributes = @{NSForegroundColorAttributeName:[UIColor blackColor],NSFontAttributeName:font,NSParagraphStyleAttributeName:style}; [attributedString addAttributes:attributes range:NSMakeRange(0, [attributedString length])]; CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)attributedString); if (numberOfLines == 0) { CGSize size = CTFramesetterSuggestFrameSizeWithConstraints(framesetter, CFRangeMake(0, 0), NULL, CGSizeMake(width, 100000000), NULL); size = CGSizeMake(ceilf(size.width), ceilf(size.height)); CFRelease(framesetter); return size; } CGRect drawingRect = CGRectMake(0, 0, width, 100000000); CGMutablePathRef path = CGPathCreateMutable(); CGPathAddRect(path, NULL, drawingRect); CTFrameRef frameRef = CTFramesetterCreateFrame(framesetter,CFRangeMake(0,0), path, NULL); CFArrayRef lines = CTFrameGetLines(frameRef); long linesNumber = (long)CFArrayGetCount(lines); if (linesNumber < 1) {//没有内容 CGPathRelease(path); CFRelease(frameRef); CFRelease(framesetter); return CGSizeZero; } numberOfLines = (numberOfLines == 0) ? linesNumber : MIN(linesNumber, numberOfLines); CGPoint lineOrigins[numberOfLines]; CTFrameGetLineOrigins(frameRef,CFRangeMake(0,numberOfLines), lineOrigins); long lastLineNumber = MAX(numberOfLines - 1, 0); CGPoint lineOrigin = lineOrigins[lastLineNumber];//最后一行line的位置 CTLineRef line = CFArrayGetValueAtIndex(lines, lastLineNumber); CGFloat ascent; CGFloat descent; CGFloat leading; CTLineGetTypographicBounds(line, &ascent, &descent, &leading); /* CGFloat height = drawingRect.size.height - floorf(lineOrigin.y) + ceilf(lineDescent); if ([[UIDevice currentDevice].systemVersion floatValue] >= 10.0) { height += ceilf(lineAscent / 2.0) + 2; } */ CGFloat height = ceilf(drawingRect.size.height - lineOrigin.y + descent + leading); if ([[UIDevice currentDevice].systemVersion floatValue] >= 10.0) { height += ceilf(descent); } CGPathRelease(path); CFRelease(frameRef); CFRelease(framesetter); return CGSizeMake(drawingRect.size.width, height); } @end
相关文章推荐
- 超过单元格长度的文本用省略号表示,利用title属性实现鼠标移上去会显示全文,但有时候只看到一部分
- IOS UILabel单行显示省略号(个人)
- IOS - 富文本实现在UILabel中显示图片
- OpenLayers3基础教程之实现地图显示功能
- CSS基础:text-overflow:ellipsis溢出文本显示省略号的详细方法_CSS教程
- IOS基础-UINAVIGATIONCONTROLLER-不写代码实现分层显示
- CSS基础:text-overflow:ellipsis溢出文本显示省略号的详细方法_CSS教程
- iOS开发零基础教程之UILabel的新初始化方法
- iOS Context 基础教程 (二)
- iOS Context 基础教程 (一)
- Delphi组件开发教程指南(6)实现一个模拟动画显示控件
- ASP基础教程:ADO存取数据库时如何分页显示
- 字符串处理是许多程序中非常重要的一部分,它们可以用于文本显示,数据表示,查找键和很多目的.在Unix下,用户可以使用正则表达式的强健功能实现这些 目的,从Java1.4起,Java核心API就引入了java.util.regex程序包,它是一种有价值的基础
- CSS基础:text-overflow:ellipsis溢出文本显示省略号的详细方法
- Android基础教程(一)之------更改与显示文字标签TextView标签的使用
- iPhone开发基础之动画显示图片的实现
- IOS开发基础之──双缓冲的实现
- Android基础教程(一)之------更改与显示文字标签TextView标签的使用
- ASP基础教程:ADO存取数据库时如何分页显示
- Android基础教程(一)之------更改与显示文字标签TextView标签的使用