5

我正在尝试解决这个问题一个星期,并且我已经测试了我脑海中的很多想法,但我无法正确计算NSString自定义字体的大小。

我有UITextView一个包含文本和一个UIView在其上绘制行号的UITextView. 问题是NSString UIKitAdditions 在计算NSString.

在图片中,您可以在第 7 行清楚地看到,这是在渲染时带有换行符的行UITextView,之后所有行都受到影响。

模拟器截图

我使用的字体是Adob​​e Source Code Pro

我已经尝试了NSString UIKitAdditions 中的所有方法,但均未成功。

sizeWithFont

sizeWithFont:forWidth:lineBreakMode:

sizeWithFont:minFontSize:actualFontSize:forWidth:lineBreakMode:

我还尝试用四个空格替换字符串中的所有制表符,它有帮助,但它仍然不能一直工作。对于某些行,它有帮助,但对于某些行则没有。

任何建议如何NSString正确计算高度?CoreText也许?

一张小纸条。我也尝试通过使用来自UITextInput协议的几何命中测试方法来解决这个问题,当它们工作时,模拟器上的 cpu 负载是 100%,所以在真实设备上它会杀死应用程序,特别是如果我加载大约 1500+ 的文件代码行。

这是我用于LineNumbersView.m的代码要点。

4

1 回答 1

1

假设UITextView和 Core Text 总是完全一致,那么后者绝对是一个解决方案,尽管对于这个问题并不是非常简单。

你:

  1. 在主视图中创建文本的属性字符串,并在整个范围内设置适当的字体;
  2. 为属性字符串创建一个合适的框架设置器(使用CTFramesetterCreateWithAttributedString);
  3. 创建一个CGPath描述字符串将被绘制到的绘图区域(作为 aUIBezierPath然后获取CGPath属性或通过创建一个并使用CGPathAddRect);
  4. 因此,从 framesetter 加上路径加上您感兴趣的字符串的子范围创建一个框架,这可能就是全部(参见 参考资料CTFramesetterCreateFrame);
  5. 然后,您可以从框架中获取CFArray它将输出的单个行(使用CTFrameGetLines),尽管这些是屏幕上的排版行而不是您的源代码行;
  6. 对于每一行,您可以获得它包含的原始字符串的范围(使用CTLineGetStringRange),允许您确定在原始换行符之后立即开始的字符串,而不是由于自动换行;
  7. 您还可以获得一个由CGPoints 组成的 C 数组,其中每个代表屏幕上一行 ( CTFrameGetLineOrigins) 的原点;通过使用您在 (6) 中学到的内容来查找位置,您可以获得相关行的屏幕原点。

为了增加乐趣,Core Text 的像素输出在 OS X 和 iOS 上是相同的。但是 OS X 认为屏幕的原始位置是左下角,就像方格纸一样。iOS 将其视为左上角,如英语阅读顺序。粗略的净效果是在 iOS Core Text 上颠倒绘制。所以你需要考虑到这一点。在 iOS 术语中,您显然会看到第一行位于框架的最底部,第二行位于其上方的一行,依此类推。您需要翻转这些坐标。

即使你跳过了这么多圈,它也可能最终只有一百行左右的代码。

于 2012-11-25T21:42:02.170 回答