ios - NSAttributedString背景颜色和圆角

标签 ios objective-c uiview quartz-graphics nsattributedstring

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

基本上,我需要在自定义UIView中实现这样的效果(图像已附加-注意一侧的圆角):


我在想使用的方法是:


使用“核心文字”获取字形运行。
检查高光范围。
如果当前运行在突出显示范围内,则在绘制字形运行之前,绘制一个带有圆角和所需填充颜色的背景矩形。
绘制字形运行。


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

不能使用UIWebView,因此我必须在自定义的UIView中进行操作。

我的问题是,这是最好的使用方法,我走在正确的轨道上吗?还是我错过了重要的事情或以错误的方式去做?

最佳答案

我设法达到了上述效果,所以以为我会给出同样的答案。

如果有人对提高此效果有任何建议,请随时做出贡献。我将确保将您的答案标记为正确的答案。 :)

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

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

对于此答案,让我们假设我添加了一个名为@"MyRoundedBackgroundColor"且值为[UIColor greenColor]的自定义属性。

对于后续步骤,您需要对CoreText如何完成工作有基本的了解。查看Apple's Core Text Programming Guide了解什么是帧/线/字形运行/字形等。

因此,步骤如下:


创建一个自定义UIView子类。
具有接受NSAttributedString的属性。
使用该CTFramesetter实例创建一个NSAttributedString
覆盖drawRect:方法
CTFrame创建一个CTFramesetter实例。


您需要提供一个CGPathRef来创建CTFrame。使该CGPath与您要在其中绘制文本的框架相同。

获取当前图形上下文并翻转文本坐标系。
使用CTFrameGetLines(...),获取刚创建的CTFrame中的所有行。
使用CTFrameGetLineOrigins(...),获取CTFrame的所有行原点。
启动for loop-为CTLine数组中的每一行...
使用CTLine将文本位置设置为CGContextSetTextPosition(...)的开头。
使用CTLineGetGlyphRuns(...)CTRunRef获取所有字形运行(CTLine)。
启动另一个for loop-为CTRun数组中的每个glyphRun ...
使用CTRunGetStringRange(...)获取运行范围。
使用CTRunGetTypographicBounds(...)获取印刷范围。
使用CTLineGetOffsetForStringIndex(...)获取运行的x偏移。
使用从上述函数返回的值来计算边界rect(我们称其为runBounds)。


记住-CTRunGetTypographicBounds(...)需要指向变量的指针来存储文本的“上升”和“下降”。您需要添加这些值以获得运行高度。

使用CTRunGetAttributes(...)获取运行的属性。
检查属性字典是否包含您的属性。
如果您的属性存在,请计算需要绘制的矩形的边界。
核心文本在基线处具有行起点。我们需要从文本的最低点绘制到最高点。因此,我们需要针对下降进行调整。
因此,从我们在步骤16(runBounds)中计算的边界矩形中减去下降。
现在有了runBounds,我们知道要绘制的区域-现在我们可以使用任何CoreGraphis / UIBezierPath方法来绘制并填充具有特定圆角的矩形。


UIBezierPath有一个名为bezierPathWithRoundedRect:byRoundingCorners:cornerRadii:的便利类方法,可让您舍入特定的角。您可以在第二个参数中使用位掩码指定拐角。

现在您已经填充了矩形,只需使用CTRunDraw(...)绘制字形即可。
庆祝创建您的自定义属性的胜利-喝啤酒或其他东西! :D


关于检测属性范围是否跨越多个运行,当第一个运行遇到该属性时,可以获取自定义属性的整个有效范围。如果发现属性的最大有效范围的长度大于运行的长度,则需要在右侧绘制尖角(用于从左到右的脚本)。更多的数学运算将使您也可以检测下一行的高光拐角样式。 :)

附件是效果的屏幕截图。顶部的框是标准的UITextView,为此我设置了attributedText。底部的框是使用上述步骤实现的框。为两个textView设置了相同的属性字符串。


再说一次,如果有比我使用的方法更好的方法,请告诉我! :D

希望这对社区有所帮助。 :)

干杯!

关于ios - NSAttributedString背景颜色和圆角,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48938139/

相关文章:

ios - UIView 无法在具有自动布局的 UIScrollView 中正确居中

c# - 带负号 (-) 和点号 (.) 的数字键盘

ios - iOS 会允许来自蓝牙外围设备的警报吗?

iphone - UIButton TouchUpInside/TouchUpOutside 并不总是被调用?

ios - 从容器 View 的 View Controller 中,如何访问包含容器的 View Controller ?

objective-c - 通过 iOS Objective-C 2.0 解析 Google Search API XML 结果

objective-c - 如何从 Tweetbot 制作一个像这样的 NSWindow?

ios - 在以编程方式创建的 UIView 层次结构之上添加 subview

objective-c - xcode 在同一窗口中打开 "click here to view symbol declaration"

swift - 如何像 Popoverview 一样在 Viewcontroller 上显示 UIViewController