如何突出CoreText与改变高亮颜色?

我有一个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中,我有一些文本属性给文本着色。

我需要帮助的是在概念上,这应该如何实现? 我很困惑所有绘制框架,图层等各种方法。我试图回顾几本书和其他资源,但我觉得我错过了一些基本的东西。

这是我的要求:

  1. 明显的亮点需要重新绘制到新的位置的方向变化。
  2. 高亮颜色需要能够以个人高亮为基础以编程方式进行更改。
  3. 理想的性能,我不想重新绘制整个CoreText UIView,当我只是改变一个突出显示的高亮颜色。
  4. 单个Rects必须能够组合在一起形成一个单独的亮点,因为亮点可以覆盖超出单个CTLine的范围。
  5. 最后,我想在CoreText视图上实现UIMenuController,所以我相信高亮必须绘制在CoreText UIView下面?

我将不胜感激任何帮助。

这是我迄今为止所尝试的:

我添加了一个新的UIView作为子视图到UIScrollView来包含高光。 然后我自己添加单独的UIViews的高光。 当我创build虚拟“testing”突出显示时,它们正确显示在CoreText视图下。 我也可以轻松地改变高光颜色。 但是,当我从CoreText视图获取关于线条的实际信息以创build真正的高光时,它将返回零线。 这可能是因为drawRect还没有完成绘图还是别的?

这里有一些问题:

  1. 我应该添加一个UIView作为一个子视图到UIScrollView,以包含每个单独突出显示的附加子视图的所有高亮? 然后,将每个高亮UIView存储在一个嵌套的NSArray?
  2. 如果我更改CoreText UIView下的高亮颜色,是否会导致整个UIView被重绘? 如果是这样,我怎么devise这个?
  3. 确实,如果我想让CoreText UIView接收UIMenuController的input,那么我必须将高亮对象置于CoreText UIView之下?

我见过这个开源项目:

https://github.com/Cocoanetics/NSAttributedString-Additions-for-HTML

这是令人惊讶的,但它比我需要的要复杂得多。 该代码使用CoreText呈现每个单独的字形运行,并允许突出显示,这是真棒。 但是,我试图保持我的代码简单和轻量级。 我对CoreGraphics,CoreAnimation或CoreText知之甚less。

我也看到了这个问题:

核心文本 – 从NSRange获取像素坐标

问题的答案提供了确定给定行中给定范围的Rect范围的调用。 我想我可以弄清楚这些电话。

UPDATE

这是我现在所做的。 我确信这是错误的,但这是我能find的唯一方法。

  1. 创build一个UIView作为一个容器添加到UIScrollView作为子视图。
  2. 将UIView传递给CoreTextView。 我还将一个string范围数组传递给CoreTextView,以指示应该突出显示哪些string。
  3. 添加CoreTextView作为UIScrollView的子视图。 这样,UIView在CoreTextView下。
  4. 在CoreTextView的drawRect:函数中,绘制CoreText。 然后我调用一个函数来计算亮点。
  5. 每个NSRange都会根据这些行进行检查,并计算该行中每个匹配的CGRect。
  6. CGRect用于创build一个新的UIView。 该UIView作为UIView容器的子视图添加。 它也被添加到NSArray中,以便我可以跟踪它并根据需要更改单个高亮的高亮颜色。

每次向容器添加高亮或更改颜色时,都不会调用drawRect。 但是,我知道这不是一个理想的解决scheme。 这个解决scheme的问题:

  1. 当UIViewController在CoreTextView上调用setNeedsDisplay时,无法知道何时完成绘图。 我仍然无法findcallback的方法来告诉ViewController可以继续下一个任务。
  2. 通过将UIViews添加到其他容器UIView中,drawRect技术上是在自己的矩形之外绘制项目,我知道这是一个不是的。
  3. 我相信这不是这样做的最高性能的方式,但它似乎工作得很好。

你的基本想法对突出显示来说不算太坏。 我不知道在绘制的时候是否比突出显示字形更容易,但这不是一个坏主意,可以很容易地打开和closures突出显示,所以这非常好。

而不是创build大量的意见,而不是你的核心文本到CALayer 。 然后,您可以创build额外的高亮图层来覆盖文本。 这将一切视图内的一切。 图层比视图便宜得多。 如果你只是想做“突出显示”风格突出显示,那么你可以设置backgroundColorframe的图层,你就完成了。