我设法达到了上述效果,所以想到我会为此发表一个答案。
如果任何人有任何建议,使其更有效,请随时参与。我一定会将你的答案标记为正确答案。 :)
为此,您需要将一个“自定义属性”添加到NSAttributedString
。
基本上,这意味着您可以添加任何键值对,只要它是可以添加到NSDictionary
实例的东西即可。如果系统无法识别该属性,则它什么也不做。作为开发人员,您需要为该属性提供自定义实现和行为。
就本答案而言,我们假设我已添加名为@"MyRoundedBackgroundColor"
的自定义属性,其值为[UIColor greenColor]
。
对于下面的步骤,您需要对CoreText
如何完成任务有基本的了解。退房Apple's Core Text Programming Guide理解什么是帧/线/字形运行/字形等
所以,这里的步骤:
- 创建一个自定义UIView子类。
- 有财产接受
NSAttributedString
。
- 使用那个
NSAttributedString
实例创建一个CTFramesetter
。
- 重写
drawRect:
方法
- 从
CTFramesetter
创建CTFrame
实例。
- 您需要输入
CGPathRef
才能创建CTFrame
。使该CGPath
与您希望绘制文本的框架相同。
- 获取当前图形上下文并翻转文本坐标系。
- 使用
CTFrameGetLines(...)
,获取您刚刚创建的CTFrame
中的所有行。
- 使用
CTFrameGetLineOrigins(...)
,获取CTFrame
的所有行起始位置。
- 启动
for loop
- 为CTLine
阵列中的每一行...
- 设置文本位置到
CTLine
使用CGContextSetTextPosition(...)
开始。
- 使用
CTLineGetGlyphRuns(...)
从CTLine
获得所有雕文运行(CTRunRef
)。的CTRun
阵列中的每个glyphRun ...
- 获取使用
CTRunGetStringRange(...)
运行的范围 -
- 启动另一个
for loop
。
- 使用
CTRunGetTypographicBounds(...)
获得印刷边界。
- 使用
CTLineGetOffsetForStringIndex(...)
获取运行的x偏移量。
- 使用上述函数返回的值计算边界矩(我们称之为
runBounds
)。
- 记住 -
CTRunGetTypographicBounds(...)
需要指向变量的指针来存储文本的“上升”和“下降”。你需要添加这些来获得运行高度。
- 使用
CTRunGetAttributes(...)
获取运行属性。
- 检查属性字典是否包含您的属性。
- 如果您的属性存在,请计算需要绘制的矩形的边界。
- 核心文本在基线处具有线条起点。我们需要从文本的最低点拉到最高点。因此,我们需要调整下降。
- 因此,从我们在步骤16(
runBounds
)中计算的边界矩来减去下降。
- 现在我们有了
runBounds
,我们知道我们要绘制什么区域 - 现在我们可以使用任何CoreGraphis
/UIBezierPath
方法绘制并填充具有特定圆角的矩形。
UIBezierPath
有一个方便的类方法bezierPathWithRoundedRect:byRoundingCorners:cornerRadii:
可以让你找出特定的角落。您可以使用第二个参数中的位掩码指定角点。
- 既然您已经填写了矩形,只需使用
CTRunDraw(...)
绘制字形运行即可。
- 庆祝创建自定义属性的胜利 - 喝一杯啤酒或其他东西!:d
关于检测的属性范围扩展多次运行,就可以得到整个有效范围内的自定义属性时,第一次运行遇到属性。如果您发现属性的最大有效范围的长度大于您的跑步长度,则需要在右侧绘制尖角(用于从左至右的脚本)。更多的数学计算可以让你检测下一行的高光角部样式。 :)
附加是效果的屏幕截图。顶部的框是标准UITextView
,为此我设置了归档文本。底部的盒子是使用上述步骤实施的盒子。两个textView都设置了相同的属性字符串。
再一次,如果有比我用过的更好的方法,请让我知道! :D
希望这有助于社区。 :)
干杯!
你好。谢谢你的评论。 :)我不认为NSLayoutManager在iOS6中可用。 iOS6有CTFrameSetter,它会给我CTFrame - > CTLine - > CTGlyph。如果我正确得到所需文本的范围,我可以绘制矩形,然后告诉CTFrame绘制自己。 – codeBearer 2013-05-05 17:38:39
对不起,是的。也许尝试textView-> selectedRange和' - [UITextInput selectionRectsForRange:]' – nielsbot 2013-05-05 19:17:32
你可以吗? 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