NSAttributedString背景颜色和圆角 [英] NSAttributedString background color and rounded corners
问题描述
我对自定义 UIView
的圆角和文字背景颜色有疑问。
I have a question regarding rounded corners and text background color for a custom UIView
.
基本上,我需要在自定义UIView中实现这样的效果(图像附加 - 注意一侧的圆角):
Basically, I need to achieve an effect like this (image attached - notice the rounded corners on one side) in a custom UIView:
我认为使用的方法是:
- 使用核心文字获取字形运行。
- 检查高亮范围。
- 如果当前运行在高亮范围内,则绘制背景在绘制字形运行之前,圆角和所需填充颜色的矩形。
- 绘制字形运行。
- Use Core Text to get glyph runs.
- Check highlight range.
- If the current run is within the highlight range, draw a background rectangle with rounded corners and desired fill color before drawing the glyph run.
- Draw the glyph run.
但是,我不确定这是否是唯一的解决方案(或者就此而言,这是否是最有效的解决方案)。
However, I'm not sure whether this is the only solution (or for that matter, whether this is the most efficient solution).
使用 UIWebView
不是一个选项,所以我必须在自定义 UIView
中进行。
Using a UIWebView
is not an option, so I have to do it in a custom UIView
.
我的问题是,我这是最好的使用方法,我是否走在正确的轨道上?或者我错过了一些重要的事情或以错误的方式去做了什么?
My question being, is this the best approach to use, and am I on the right track? Or am I missing out something important or going about it the wrong way?
推荐答案
我设法达到了上述效果,所以想到了我会发布相同的答案。
I managed to achieve the above effect, so thought I'd post an answer for the same.
如果有人有任何关于提高效率的建议,请随时提供帮助。我一定会把你的答案标记为正确答案。 :)
If anyone has any suggestions about making this more effective, please feel free to contribute. I'll be sure to mark your answer as the correct one. :)
为此,您需要在 NSAttributedString
中添加自定义属性。
For doing this, you'll need to add a "custom attribute" to NSAttributedString
.
基本上,这意味着您可以添加任何键值对,只要它可以添加到 NSDictionary
实例。如果系统无法识别该属性,则不执行任何操作。作为开发人员,您可以为该属性提供自定义实现和行为。
Basically, what that means is that you can add any key-value pair, as long as it is something that you can add to an NSDictionary
instance. If the system does not recognize that attribute, it does nothing. It is up to you, as the developer, to provide a custom implementation and behavior for that attribute.
出于本答案的目的,我们假设我已添加一个自定义属性: @MyRoundedBackgroundColor
,其值为 [UIColor greenColor]
。
For the purposes of this answer, let us assume I've added a custom attribute called: @"MyRoundedBackgroundColor"
with a value of [UIColor greenColor]
.
对于接下来的步骤,您需要基本了解 CoreText
如何完成工作。查看 Apple的核心文本编程指南,用于了解帧/行/字形运行/字形等。
For the steps that follow, you'll need to have a basic understanding of how CoreText
gets stuff done. Check out Apple's Core Text Programming Guide for understanding what's a frame/line/glyph run/glyph, etc.
所以,步骤如下:
- 创建自定义UIView子类。
- 拥有接受
NSAttributedString <的属性/ code>。
- 使用
NSAttributedString
创建CTFramesetter
实例。 - 覆盖
drawRect:
方法 - 创建
来自
实例。CTFramesetter
的CTFrame
- Create a custom UIView subclass.
- Have a property for accepting an
NSAttributedString
. - Create a
CTFramesetter
using thatNSAttributedString
instance. - Override the
drawRect:
method - Create a
CTFrame
instance from theCTFramesetter
.
- 您需要提供
CGPathRef
来创建CTFrame
。使CGPath
与您希望绘制文本的框架相同。
- You will need to give a
CGPathRef
to create theCTFrame
. Make thatCGPath
to be the same as the frame in which you wish to draw the text.
CTFrameGetLines(...)
,获取您刚刚创建的 CTFrame
中的所有行。 CTFrameGetLineOrigins(...)
,获取 CTFrame
的所有行原点。 for循环
- 对于 CTLine
... CTLine
使用 CGContextSetTextPosition(...)
。 CTLineGetGlyphRuns(...)
从 CTLine $ c获取所有字形运行( CTRunRef
) $ c>。
CTRun $数组中的每个glyphRun启动另一个 for循环
c $ c> ...
CTRunGetStringRange(...)
获取运行范围。 CTRunGetTypographicBounds(...)
。 CTLineGetOffsetForStringIndex获取运行的x偏移量( ...)
。 runBounds
)从上述功能。 CTFrameGetLines(...)
, get all the lines in the CTFrame
you just created.CTFrameGetLineOrigins(...)
, get all the line origins for the CTFrame
.for loop
- for each line in the array of CTLine
...CTLine
using CGContextSetTextPosition(...)
.CTLineGetGlyphRuns(...)
get all the Glyph Runs (CTRunRef
) from the CTLine
.for loop
- for each glyphRun in the array of CTRun
...CTRunGetStringRange(...)
.CTRunGetTypographicBounds(...)
.CTLineGetOffsetForStringIndex(...)
.runBounds
) using the values returned from the aforementioned functions.
- 记住 -
CTRunGetTypographicBounds(...)
需要指向变量的指针来存储ascent和文本的下降。您需要添加这些以获得运行高度。
- Remember -
CTRunGetTypographicBounds(...)
requires pointers to variables to store the "ascent" and "descent" of the text. You need to add those to get the run height.
CTRunGetAttributes(。获取运行的属性)。 ..)
。 runBounds
)。 runBounds
,我们知道我们想要绘制哪个区域 - 现在我们可以使用任何 CoreGraphis
/ UIBezierPath
绘制和填充具有特定圆角的矩形的方法。 CTRunGetAttributes(...)
.runBounds
).runBounds
, we know what area we want to paint - now we can use any of the CoreGraphis
/UIBezierPath
methods to draw and fill a rect with specific rounded corners.
-
UIBezierPath
有一个名为的便捷类方法bezierPathWithRoundedRect:byRoundingCorners:cornerRadii:
让你绕过特定角落。您可以在第二个参数中使用位掩码指定角点。
UIBezierPath
has a convenience class method calledbezierPathWithRoundedRect:byRoundingCorners:cornerRadii:
that let's you round specific corners. You specify the corners using bit masks in the 2nd parameter.
CTRunDraw(...)
。关于检测到属性范围超过多次运行,您可以在第1次获取自定义属性的整个有效范围run遇到属性。如果您发现属性的最大有效范围的长度大于运行的长度,则需要在右侧绘制尖角(对于从左到右的脚本)。更多的数学运算将让您检测下一行的高光转角样式。 :)
Regarding detecting that the attribute range extends over multiple runs, you can get the entire effective range of your custom attribute when the 1st run encounters the attribute. If you find that the length of the maximum effective range of your attribute is greater than the length of your run, you need to paint sharp corners on the right side (for a left to right script). More math will let you detect the highlight corner style for the next line as well. :)
附件是效果的屏幕截图。顶部的框是标准的 UITextView
,我为其设置了attributionText。底部的框是使用上述步骤实现的框。已为textViews设置了相同的属性字符串。
Attached is a screenshot of the effect. The box on the top is a standard UITextView
, for which I've set the attributedText. The box on the bottom is the one that has been implemented using the above steps. The same attributed string has been set for both the textViews.
再说一次,如果有比我使用过的方法更好的方法,请告诉我! :D
Again, if there is a better approach than the one that I've used, please do let me know! :D
希望这有助于社区。 :)
Hope this helps the community. :)
干杯!
这篇关于NSAttributedString背景颜色和圆角的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!