获取NSString的可见字符的范围

我正在尝试获取UILabel中可见字符的范围。 所以例如,如果我有文字

Lorem ipsum dolor sit amet,consetetur sadipscing elitr,sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat,sed diam voluptua。 在vero eos et accusam et justo duo dolores et ea rebum。 没有海takimata sanctus est Lorem ipsum dolor坐amet。 Lorem ipsum dolor sit amet,consetetur sadipscing elitr,sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat,sed diam voluptua。 在vero eos et accusam et justo duo dolores et ea rebum。 没有海takimata sanctus est Lorem ipsum dolor坐amet。

和我的UILabel只设置为宽度和高度100,100是否有目标C中的预定义方法来获取可见字符的范围?

Lorem ipsum dolor sit amet,consetetur sadipscing elitr,sed diam nonumy eirmod tempor invidunt

其他答案指出,有多less文本可能有近似值 ,没有真正的方法来获取由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

如果你假设结束,你可以强制截断成为自己的字形运行,并获得第二个到最后一个文本运行的结束位置。 如果您将其与删除的字符数进行比较,则可以获取新的string:

  1. 为截断string添加一个虚拟属性:

     NSMutableDictionary *truncationTokenStringAttributes = [self.truncationTokenStringAttributes mutableCopy]; if (!truncationTokenStringAttributes) { truncationTokenStringAttributes = [[attributedString attributesAtIndex:(NSUInteger)truncationAttributePosition effectiveRange:NULL] mutableCopy]; } truncationTokenStringAttributes[@"DummyAttributeToForceNewRun"] = @1; 
  2. 创buildtruncatedLine之后,将第二个和最后一个运行结束位置比较为法线长度:

     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将包含所呈现的实际文本,包括截断符号。 我已经尝试了这种各种string,并已经拿出了一致的结果。