我正在尝试获取UILabel中可见字符的范围。例如,如果我有文本
Lorem ipsum dolor sit amet,consetetur sadipscing elitr,sed diam nonomy eirmod tempor invdunt ut labore et dolore magna aliquyam erat,sed diam-voluptua。在vero eos et accusam et justo duo dolores et ea reum。这是一个很好的例子,没有海洋动物保护区。Lorem ipsum dolor sit amet,consetetur sadipscing elitr,sed diam nonomy eirmod tempor invdunt ut labore et dolore magna aliquyam erat,sed diam-voluptua。在vero eos et accusam et justo duo dolores et ea reum。这是一个很好的例子,没有海洋动物保护区。
并且我的UILabel仅设置为宽度和高度100100。目标C中是否有预定义的方法来仅获取可见字符的范围?
Lorem ipsum dolor sit amet,consetetur sadipscing elitr,sed diam nonomy eirmod tempor invidunt。。。
其他答案指出,对于文本的大小,可能存在近似值,但没有真正的方法来获得UILabel
渲染的实际文本,因为它不会公开渲染过程的任何输出。
如果通过类似TTTAttributedLabel
的方式渲染文本,则可以查看渲染过程内部,并注入一些代码以获取有关所渲染文本的信息。
例如,-[TTTAttributedLabel drawFramesetter:attributedString:textRange:inRect:context:]
通过生成CTFrameRef
来使用CoreText渲染实际文本。CTFrameRef的任务是布置文本,并报告哪些文本适合,哪些不适合。
忽略截断:
如果您不关心由于截断而丢失字符的事实,则可以调用CTFrameGetVisibleStringRange
来获取显示的字符范围。这个功能背后的想法是,像多列文本布局这样的东西需要知道下一帧从哪里开始:
CFRange actuallyRenderedRange = CTFrameGetVisibleStringRange(frame);
NSString *actuallyRenderedText = [attributedString.string substringWithRange:NSMakeRange(actuallyRenderedRange.location, actuallyRenderedRange.length)];
考虑截断:
截断很复杂,对于CoreText来说是一个黑盒。对于未截断的行,标签可以只渲染CTFrameGetLines
中的行。对于截断的行,它必须使用CTLineCreateTruncatedLine
,指定截断线、截断点和截断标记(…)。但是,一旦有了这行,就没有直接的方法来获取截断的文本,因为它可能发生在行的开头、结尾或中间。看见https://stackoverflow.com/a/5672594/860000.
如果假设结束,则可以强制截断为其自己的字形运行,并获取倒数第二个文本运行的结束位置。如果你将其与删除的字符数进行比较,你可以得到新的字符串:
在截断字符串中添加一个伪属性:
NSMutableDictionary *truncationTokenStringAttributes = [self.truncationTokenStringAttributes mutableCopy]; if (!truncationTokenStringAttributes) { truncationTokenStringAttributes = [[attributedString attributesAtIndex:(NSUInteger)truncationAttributePosition effectiveRange:NULL] mutableCopy]; } truncationTokenStringAttributes[@"DummyAttributeToForceNewRun"] = @1;
创建
truncatedLine
后,将倒数第二个行程结束位置与正常线路长度进行比较:CFArrayRef truncatedLineRuns = CTLineGetGlyphRuns(truncatedLine); CFIndex truncatedLineRunCount = CFArrayGetCount(truncatedLineRuns); CFIndex numberOfCharactersRemoved; CFIndex untruncatedLineLength = CTLineGetStringRange(line).length; if (truncatedLineRunCount > 1) { CTRunRef lastRealRun = CFArrayGetValueAtIndex(truncatedLineRuns, truncatedLineRunCount - 2); CFRange lastRunRange = CTRunGetStringRange(lastRealRun); numberOfCharactersRemoved = untruncatedLineLength - (lastRunRange.length + lastRunRange.location); } else { numberOfCharactersRemoved = untruncatedLineLength; // Everything was removed. } if (numberOfCharactersRemoved > 0) { actuallyRenderedText = [actuallyRenderedText substringToIndex:actuallyRenderedText.length - numberOfCharactersRemoved]; } actuallyRenderedText = [actuallyRenderedText stringByAppendingString:truncationTokenString];
当函数完成时,actuallyRenderedText
将包含所呈现的实际文本,包括截断符号。我已经为各种字符串尝试过了,结果是一致的。