我正在尝试使用[NSAttributedString drawWithRect:options:context:]
方法在后台渲染一些文字,并且我正在为(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading| NSStringDrawingTruncatesLastVisibleLine | NSLineBreakByWordWrapping)
传递选项。如果我的字符串超过两行(我计算了矩形的最大高度),我的文字会被...
截断。
但是效果很好,而不是...
,我需要使用...more
进行截断(最后使用"更多")。
所有渲染必须在后台线程上完成,因此任何UI组件都是不可能的。并且请不要推荐TTTAttributedLabel
,因为我首先试图摆脱它,因为它导致在我的应用程序中滚动可怕的性能(已经尝试过)。
在后台线程中绘制字符串时,如何使用自定义截断标记?
答案 0 :(得分:0)
可能不是最有效的,但我最终是这样的:
检查字符串的大小是否具有所需的宽度和没有高度限制(在绘制方法中使用MAXFLOAT
作为边界矩形的高度):
NSStringDrawingOptions drawingOptions = (NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading);
[stringToDraw boundingRectWithSize:maximumSize options:drawingOptions context:nil].size;
我知道字体大小,检查结果大小的高度,检查它是否高于预定高度,这表明它是否超过两行。
如果它超过两行,请使用https://stackoverflow.com/a/26806991/811405上的答案的修改版本,获取...more
应该大致开始的矩形点处的字符索引( point位于原始文本矩形的第二行右下角附近):
//this string spans more than two lines.
NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:attributedString];
NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
[textStorage addLayoutManager:layoutManager];
// init text container
NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:size];
textContainer.lineFragmentPadding = 0;
textContainer.maximumNumberOfLines = 2;
textContainer.lineBreakMode = NSLineBreakByClipping;
[layoutManager addTextContainer:textContainer];
CGPoint moreStartLocation = CGPointMake(size.width - 60, 30); //35 magic number
NSUInteger characterIndex = [layoutManager characterIndexForPoint:moreStartLocation
inTextContainer:textContainer
fractionOfDistanceBetweenInsertionPoints:NULL];
stringToDraw = [attributedString attributedSubstringFromRange:NSMakeRange(0, characterIndex)].mutableCopy;
[stringToDraw appendAttributedString:self.truncationText];
size = CGSizeMake(size.width, 35);
将原始字符串截断为字符(可选:还可以从限制中找到最后一个空格(例如空格,换行符)字符,并从该点获取子字符串以避免单词剪切)。将“... more”添加到原始字符串。 (文本可以是任何属性,具有任何属性。只需确保它适合两行中的结果矩形。我已将其固定为60px,但也可以获得所需截断字符串的大小,并使用其宽度精确找到最后一个字符)
像往常一样渲染新字符串(以“... more”结尾):
UIGraphicsBeginImageContextWithOptions(contextSize, YES, 0);
[stringToDraw drawWithRect:rectForDrawing options:drawingOptions context:nil];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
这个方法的好处在于,由于我们没有触及UIKit(UIGraphics...
函数和UIImage
是线程安全的),我们可以在后台线程/队列中执行整个过程。我正在使用它在背景中使用属性/链接等预渲染一些文本内容,否则在滚动时在UI线程中占用一两帧,并且它完美地工作。