获取NSString的可见字符范围

时间:2014-09-17 16:48:32

标签: ios objective-c

我想在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。 Stet clita kasd gubergren,no sea takimata sanctus est Lorem ipsum dolor sit 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。 Stet clita kasd gubergren,no sea takimata sanctus est Lorem ipsum dolor sit amet。

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

  

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

1 个答案:

答案 0 :(得分:0)

其他答案指出,文本适合多少可能有近似值,没有真正的方法来获取由{{1}呈现的实际文本因为它不会暴露渲染过程的任何输出。

如果您通过类似UILabel的内容呈现文本,则可以查看渲染过程并注入一些代码以获取有关已呈现文本的信息。

例如,TTTAttributedLabel通过生成-[TTTAttributedLabel drawFramesetter:attributedString:textRange:inRect:context:]使用CoreText呈现实际文本。 CTFrameRef的任务是布置文本并报告哪些文本适合,哪些文本不适合。

忽略截断:

如果您不关心截断字符丢失的事实,可以调用CTFrameRef来获取显示的字符范围。这个函数背后的想法是像多列文本布局这样的东西需要知道从下一帧开始的位置:

CTFrameGetVisibleStringRange

考虑截断:

Truncation很复杂,是一个关于CoreText的黑盒子。对于非截断线,标签只能从CFRange actuallyRenderedRange = CTFrameGetVisibleStringRange(frame); NSString *actuallyRenderedText = [attributedString.string substringWithRange:NSMakeRange(actuallyRenderedRange.location, actuallyRenderedRange.length)]; 渲染线。对于截断的行,它必须使用CTFrameGetLines,指定截断行,截断点和截断标记(...)。但是,一旦你有了这条线,就没有直接的方法来获得切断的文本,因为它可能发生在线的开始,结束或中间。请参阅https://stackoverflow.com/a/5672594/860000

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

  1. 向截断字符串添加虚拟属性:

    CTLineCreateTruncatedLine
  2. 创建NSMutableDictionary *truncationTokenStringAttributes = [self.truncationTokenStringAttributes mutableCopy]; if (!truncationTokenStringAttributes) { truncationTokenStringAttributes = [[attributedString attributesAtIndex:(NSUInteger)truncationAttributePosition effectiveRange:NULL] mutableCopy]; } truncationTokenStringAttributes[@"DummyAttributeToForceNewRun"] = @1; 后,将第二个到上一个运行结束位置与正常行长度进行比较:

    truncatedLine
  3. 当函数完成时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]; 将包含呈现的实际文本,包括截断符号。我已经尝试过各种各样的字符串,这就产生了一致的结果。