我需要一个带有多行属性文本的UILabel subcass,支持链接,粗体样式等.我还需要带有省略号的尾部截断.支持内部UILabels属性文本开放源代码的无(TTTAttributedLabel
,OHAttributedLabel
,TTStyledTextLabel
)似乎支持为多行文本尾截断.有一个简单的方法来获得这个吗?
Toy*_*dor 38
也许我错过了什么,但有什么不对吗?:
NSMutableAttributedString *text = [[NSMutableAttributedString alloc] initWithString:@"test"];
NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init];
style.lineBreakMode = NSLineBreakByTruncatingTail;
[text addAttribute:NSParagraphStyleAttributeName
value:style
range:NSMakeRange(0, text.length)];
label.attributedText = text;
Run Code Online (Sandbox Code Playgroud)
这非常有效,并且会在最后添加省略号.
Ali*_*are 13
嗨,我是开发人员OHAttributedLabel
.
没有简单的方法来实现这一点(正如我在项目的github存储库中打开的相关问题中所解释的那样),因为CoreText不提供此类功能.
执行此操作的唯一方法是使用CoreText对象(CTLine等)自己实现文本布局,而不是使用CTFrameSetter
为您执行此操作(但没有管理行截断).我们的想法是建立所有的CTLine,将它们(依赖于NSAttributedString
它包含的字形和自动换行策略)一个接一个地放置出来,并自己管理最后的省略号.
我真的很感激,如果有人提出解决方案来做这个工作,因为它似乎需要做一些工作,你必须管理一系列特殊/不寻常的情况(表情符号案例,具有奇怪指标的字体和不寻常的字形,垂直对齐,考虑到省略号本身的大小,知道何时停止).
因此,请随意挖掘并尝试自己实现线条的框架,真的很感激!
小智 9
根据我在这里及以上的网站https://groups.google.com/forum/?fromgroups=#!topic/cocoa-unbound/Qin6gjYj7XU,我提出了以下内容,效果非常好.
- (void)drawString:(CFAttributedStringRef)attString inRect:(CGRect)frameRect inContext: (CGContextRef)context
{
CGContextSaveGState(context);
// Flip the coordinate system
CGContextSetTextMatrix(context, CGAffineTransformIdentity);
CGContextTranslateCTM(context, 0, self.bounds.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
CGFloat height = self.frame.size.height;
frameRect.origin.y = (height - frameRect.origin.y) - frameRect.size.height ;
// Create a path to render text in
// don't set any line break modes, etc, just let the frame draw as many full lines as will fit
CGMutablePathRef framePath = CGPathCreateMutable();
CGPathAddRect(framePath, nil, frameRect);
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString(attString);
CFRange fullStringRange = CFRangeMake(0, CFAttributedStringGetLength(attString));
CTFrameRef aFrame = CTFramesetterCreateFrame(framesetter, fullStringRange, framePath, NULL);
CFRelease(framePath);
CFArrayRef lines = CTFrameGetLines(aFrame);
CFIndex count = CFArrayGetCount(lines);
CGPoint *origins = malloc(sizeof(CGPoint)*count);
CTFrameGetLineOrigins(aFrame, CFRangeMake(0, count), origins);
// note that we only enumerate to count-1 in here-- we draw the last line separately
for (CFIndex i = 0; i < count-1; i++)
{
// draw each line in the correct position as-is
CGContextSetTextPosition(context, origins[i].x + frameRect.origin.x, origins[i].y + frameRect.origin.y);
CTLineRef line = (CTLineRef)CFArrayGetValueAtIndex(lines, i);
CTLineDraw(line, context);
}
// truncate the last line before drawing it
if (count) {
CGPoint lastOrigin = origins[count-1];
CTLineRef lastLine = CFArrayGetValueAtIndex(lines, count-1);
// truncation token is a CTLineRef itself
CFRange effectiveRange;
CFDictionaryRef stringAttrs = CFAttributedStringGetAttributes(attString, 0, &effectiveRange);
CFAttributedStringRef truncationString = CFAttributedStringCreate(NULL, CFSTR("\u2026"), stringAttrs);
CTLineRef truncationToken = CTLineCreateWithAttributedString(truncationString);
CFRelease(truncationString);
// now create the truncated line -- need to grab extra characters from the source string,
// or else the system will see the line as already fitting within the given width and
// will not truncate it.
// range to cover everything from the start of lastLine to the end of the string
CFRange rng = CFRangeMake(CTLineGetStringRange(lastLine).location, 0);
rng.length = CFAttributedStringGetLength(attString) - rng.location;
// substring with that range
CFAttributedStringRef longString = CFAttributedStringCreateWithSubstring(NULL, attString, rng);
// line for that string
CTLineRef longLine = CTLineCreateWithAttributedString(longString);
CFRelease(longString);
CTLineRef truncated = CTLineCreateTruncatedLine(longLine, frameRect.size.width, kCTLineTruncationEnd, truncationToken);
CFRelease(longLine);
CFRelease(truncationToken);
// if 'truncated' is NULL, then no truncation was required to fit it
if (truncated == NULL)
truncated = (CTLineRef)CFRetain(lastLine);
// draw it at the same offset as the non-truncated version
CGContextSetTextPosition(context, lastOrigin.x + frameRect.origin.x, lastOrigin.y + frameRect.origin.y);
CTLineDraw(truncated, context);
CFRelease(truncated);
}
free(origins);
CGContextRestoreGState(context);
Run Code Online (Sandbox Code Playgroud)
}
这是 @Toydor 答案的 Swift 5 版本:
let attributedString = NSMutableAttributedString(string: "my String")
let style: NSMutableParagraphStyle = NSMutableParagraphStyle()
style.lineBreakMode = .byTruncatingTail
attributedString.addAttribute(NSAttributedString.Key.paragraphStyle,
value: style,
range: NSMakeRange(0, attributedString.length))
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
23736 次 |
最近记录: |