2013-05-03 438 views
39

我对自定义UIView的圆角和文本背景颜色有疑问。NSAttributedString背景颜色和圆角

基本上,我需要实现这样的效果(图像连接 - 发现一侧圆角)在自定义的UIView: Background highlight

我想的办法来使用方法是:

  • 使用核心文本来获得字形运行。
  • 选中高亮范围。
  • 如果当前运行在高亮范围内,在绘制字形运行前绘制一个带圆角和所需填充颜色的背景矩形。
  • 绘制字形运行。

但是,我不确定这是否是唯一的解决方案(或者就此而言,这是否是最有效的解决方案)。

使用UIWebView不是一个选项,所以我必须在自定义UIView

我的问题是,这是最好的方法来使用,我在正确的轨道上?或者我错过了一些重要的东西或者错误的方式?

+0

你好。谢谢你的评论。 :)我不认为NSLayoutManager在iOS6中可用。 iOS6有CTFrameSetter,它会给我CTFrame - > CTLine - > CTGlyph。如果我正确得到所需文本的范围,我可以绘制矩形,然后告诉CTFrame绘制自己。 – codeBearer 2013-05-05 17:38:39

+0

对不起,是的。也许尝试textView-> selectedRange和' - [UITextInput selectionRectsForRange:]' – nielsbot 2013-05-05 19:17:32

+0

你可以吗? 1.使标签透明 2.获取子字符串文本范围的框架(http://stackoverflow.com/questions/19417776/how-do-i-locate-the-cgrect-for-a-substring-of -text-in-a-uilabel) 3.在标签后面添加圆角矩形子视图 – Robert 2017-01-06 12:40:27

回答

47

我设法达到了上述效果,所以想到我会为此发表一个答案。

如果任何人有任何建议,使其更有效,请随时参与。我一定会将你的答案标记为正确答案。 :)

为此,您需要将一个“自定义属性”添加到NSAttributedString

基本上,这意味着您可以添加任何键值对,只要它是可以添加到NSDictionary实例的东西即可。如果系统无法识别该属性,则它什么也不做。作为开发人员,您需要为该属性提供自定义实现和行为。

就本答案而言,我们假设我已添加名为@"MyRoundedBackgroundColor"的自定义属性,其值为[UIColor greenColor]

对于下面的步骤,您需要对CoreText如何完成任务有基本的了解。退房Apple's Core Text Programming Guide理解什么是帧/线/字形运行/字形等

所以,这里的步骤:

  1. 创建一个自定义UIView子类。
  2. 有财产接受NSAttributedString
  3. 使用那个NSAttributedString实例创建一个CTFramesetter
  4. 重写drawRect:方法
  5. CTFramesetter创建CTFrame实例。
    1. 您需要输入CGPathRef才能创建CTFrame。使该CGPath与您希望绘制文本的框架相同。
  6. 获取当前图形上下文并翻转文本坐标系。
  7. 使用CTFrameGetLines(...),获取您刚刚创建的CTFrame中的所有行。
  8. 使用CTFrameGetLineOrigins(...),获取CTFrame的所有行起始位置。
  9. 启动for loop - 为CTLine阵列中的每一行...
  10. 设置文本位置到CTLine使用CGContextSetTextPosition(...)开始。
  11. 使用CTLineGetGlyphRuns(...)CTLine获得所有雕文运行(CTRunRef)。的CTRun阵列中的每个glyphRun ...
  12. 获取使用CTRunGetStringRange(...)运行的范围 -
  13. 启动另一个for loop
  14. 使用CTRunGetTypographicBounds(...)获得印刷边界。
  15. 使用CTLineGetOffsetForStringIndex(...)获取运行的x偏移量。
  16. 使用上述函数返回的值计算边界矩(我们称之为runBounds)。
    1. 记住 - CTRunGetTypographicBounds(...)需要指向变量的指针来存储文本的“上升”和“下降”。你需要添加这些来获得运行高度。
  17. 使用CTRunGetAttributes(...)获取运行属性。
  18. 检查属性字典是否包含您的属性。
  19. 如果您的属性存在,请计算需要绘制的矩形的边界。
  20. 核心文本在基线处具有线条起点。我们需要从文本的最低点拉到最高点。因此,我们需要调整下降。
  21. 因此,从我们在步骤16(runBounds)中计算的边界矩来减去下降。
  22. 现在我们有了runBounds,我们知道我们要绘制什么区域 - 现在我们可以使用任何CoreGraphis/UIBezierPath方法绘制并填充具有特定圆角的矩形。
    1. UIBezierPath有一个方便的类方法bezierPathWithRoundedRect:byRoundingCorners:cornerRadii:可以让你找出特定的角落。您可以使用第二个参数中的位掩码指定角点。
  23. 既然您已经填写了矩形,只需使用CTRunDraw(...)绘制字形运行即可。
  24. 庆祝创建自定义属性的胜利 - 喝一杯啤酒或其他东西!:d

关于检测的属性范围扩展多次运行,就可以得到整个有效范围内的自定义属性时,第一次运行遇到属性。如果您发现属性的最大有效范围的长度大于您的跑步长度,则需要在右侧绘制尖角(用于从左至右的脚本)。更多的数学计算可以让你检测下一行的高光角部样式。 :)

附加是效果的屏幕截图。顶部的框是标准UITextView,为此我设置了归档文本。底部的盒子是使用上述步骤实施的盒子。两个textView都设置了相同的属性字符串。 custom attribute with rounded corners

再一次,如果有比我用过的更好的方法,请让我知道! :D

希望这有助于社区。 :)

干杯!

+1

您是否有一些可以共享的示例代码? – ddiego 2013-05-09 23:28:16

+0

你好。通常,我会粘贴我用于任何给定实现的代码。不幸的是,我不能为这个特殊情况做同样的事情。 :(对不起, – codeBearer 2013-05-12 23:23:42

+0

我可以理解,但如果你改变了主意并想发表一些片段,那将会有所帮助,我无法按照你的指示进行操作 – ddiego 2013-05-13 16:18:45