【发布时间】:2011-07-21 15:56:55
【问题描述】:
我有一个 UIView 的子类,它实现了绘制 CoreText 的代码。在应用程序中,该 UIView 是在 UIScrollView 中绘制的。这是我目前在 drawRect 中使用的代码:呈现 NSAttributedString:
CGContextRef context = UIGraphicsGetCurrentContext();
float viewHeight = self.bounds.size.height;
CGContextTranslateCTM(context, 0, viewHeight);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextSetTextMatrix(context, CGAffineTransformMakeScale(1.0, 1.0));
CGMutablePathRef path = CGPathCreateMutable();
CGRect bounds = CGRectMake(PADDING_LEFT, -PADDING_TOP, self.bounds.size.width-20.0, self.bounds.size.height);
CGPathAddRect(path, NULL, bounds);
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFMutableAttributedStringRef)attrString);
CTFrameRef frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), path, NULL);
CFRelease(framesetter);
CFRelease(path);
CTFrameDraw(frame, context);
在我的 NSAttributedString 中,我有某些文本属性来为文本着色。
我需要帮助的是概念上的,这应该如何实现?我对绘制框架、图层等的各种方法感到困惑。我尝试查看几本书和其他资源,但我觉得我缺少一些基本的东西。
这是我的要求:
- 显然需要在改变方向时将亮点重新绘制到新位置。
- 需要能够以编程方式在单个突出显示的基础上更改突出显示颜色。
- 为了提高性能,我不想在只更改一个突出显示的突出显示颜色时重新绘制整个 CoreText UIView。
- 各个 Rect 必须能够组合在一起以形成单个突出显示,因为突出显示可以覆盖超出单个 CTLine 的范围。
- 最终,我想在 CoreText 视图上实现 UIMenuController,所以我认为必须在 CoreText UIView 下方绘制高光?
如果能提供任何帮助,我将不胜感激。
这是我迄今为止尝试过的:
我添加了一个新的 UIView 作为 UIScrollView 的子视图以包含亮点。然后,我为突出显示本身添加单独的 UIView。当我创建虚拟“测试”高亮时,它们会正确显示在 CoreText 视图下。我还可以轻松更改高亮颜色。但是,当我从 CoreText 视图获取有关线条的实际信息以创建真正的高光时,它返回零行。这可能是因为drawRect尚未完成绘制还是其他原因?
这里有一些问题:
- 我是否应该将 UIView 作为子视图添加到 UIScrollView 以包含所有亮点,并为每个单独的亮点添加额外的子视图?然后,将每个高亮 UIView 存储在嵌套的 NSArray 中?
- 如果我更改 CoreText UIView 下方突出显示的颜色,是否会导致整个 UIView 被重绘?如果是这样,我该如何设计?
- 确实,如果我希望 CoreText UIView 接收 UIMenuController 的输入,我必须将高亮对象放在 CoreText UIView 下方?
我看过这个开源项目:
https://github.com/Cocoanetics/NSAttributedString-Additions-for-HTML
它的功能令人惊叹,但比我需要的要复杂和详细得多。该代码使用 CoreText 渲染每个单独的字形运行并允许突出显示,这很棒。但是,我正在努力使我的代码保持简单和轻量级。我对 CoreGraphics、CoreAnimation 或 CoreText 知之甚少。
我也看过这个问题:
Core Text - Get Pixel Coordinates from NSRange
该问题的答案提供了用于确定给定行中给定范围的 Rect 边界的调用。我想我可以弄清楚那些电话。
更新
这是我现在所做的。我确定这是错误的,但这是我能找到使其工作的唯一方法......
- 创建一个 UIView 作为容器以作为子视图添加到 UIScrollView。
- 将 UIView 传递给 CoreTextView。我还将一个字符串范围数组传递给 CoreTextView 以指示应突出显示哪些字符串。
- 将 CoreTextView 添加为 UIScrollView 的子视图。这样,UIView 就位于 CoreTextView 之下。
- 在CoreTextView的drawRect:函数中,我绘制了CoreText。然后我调用一个函数来计算高光。
- 根据行检查每个 NSRange,并计算行中每个匹配项的 CGRect。
- CGRect 用于创建新的 UIView。该 UIView 被添加为 UIView 容器的子视图。它还被添加到 NSArray 中,以便我可以跟踪它并根据需要更改单个突出显示的突出显示颜色。
这不会在每次向容器添加高亮或更改颜色时调用 drawRect。但是,我知道这不是一个理想的解决方案。此解决方案的问题:
- 当 UIViewController 在 CoreTextView 上调用 setNeedsDisplay 时,无法知道何时完成绘制。我仍然无法找到一种方法来进行回调以告诉 ViewController 可以继续执行下一个任务。
- 通过将 UIViews 添加到另一个容器 UIView,drawRect 在技术上是在它自己的矩形之外绘制项目,我知道这是不行的。
- 我确信这不是执行此操作的最高效方式,尽管它似乎工作得很好。
【问题讨论】:
标签: iphone ios uiscrollview core-graphics core-text