使用NSAttributedString,我想在字符串的下划线下划线。以下代码无法正常工作:

let string = NSMutableAttributedString(string: "This is my string.")

string.addAttributes([.underlineStyle : NSUnderlineStyle.single],
                           range: NSRange(location: 5, length: 2))

人们期望“是”被强调。相反,UITextView布局引擎将忽略该属性,并在控制台中生成警告。该警告无助地没有提及underlineStyleNSUnderlineStyle

这个问题很普遍。 StackOverflow上有很多示例显示了正确的用法。但是,尽管我确定必须有一些答案来解释问题,但我已阅读的答案仅显示了用法的不透明示例。

提出这个问题(并在下面给出答案)是为了纪念对该问题的解释,以便将来我和其他人可以从中学习。

最佳答案

NSUnderlineStyle不是正确的类型

准确但有些无助的是,documentation解释说underlineStyle属性键采用“包含整数的NSNumber”的属性值。

此属性的值是一个NSNumber对象,其中包含
整数。此值指示文本是否带下划线,以及
对应于NSUnderlineStyle中描述的常量之一。的
此属性的默认值为styleNone。

许多读者被NSUnderlineStyle所吸引,点击它,然后找到一个类似于枚举的样式列表:singlethickpatternDashdouble等。这似乎是一个不错的Swifty解决方案。读者认为此枚举必须是指定属性值的方式,并键入上面问题中所示的代码种类。
rawValueNSUnderlineStyle属性提供正确的类型
NSUnderlineStyle不是一个枚举。它是符合OptionSet协议的结构。 OptionSet协议是设置整数位的便捷,快速方法,每个位代表二进制状态。 NSUnderlineStyle结构是该整数的包装器。它的类似于枚举的样式实际上是结构上的静态var,每个静态var返回带有嵌入式整数的NSUnderlineStyle实例,只有一位翻转以对应于所需样式。
NSAttributedString的属性字典将字面意义上的任何内容作为值,因此它很乐意接受NSUnderlineStyle的实例。但是使UITextViewUILabel工作的引擎TextKit不知道如何处理NSUnderlineStyle实例。当TextKit尝试呈现underlineStyle属性时,它需要一个整数,以便可以通过检查整数的位来确定正确的样式。

幸运的是,有一种简单的方法可以获取该整数。 rawValueNSUnderlineStyle属性对其进行出售。因此,我们的代码段的正常工作版本如下:

let string = NSMutableAttributedString(string: "This is my string.")

string.addAttributes([.underlineStyle : NSUnderlineStyle.single.rawValue],
                           range: NSRange(location: 5, length: 2))

该代码与问题代码之间的唯一区别是在“NSUnderlineStyle.single”上添加了“.rawValue”。并且,“是”下划线。

另外,rawValue属性提供的类型是Int,而不是NSNumber。文档对属性值为NSNumber的引用可能会造成混淆。在底层,为了与ObjC互操作,NSAttributedStringInt包装在NSNumber中。不需要(或没有好处?)将Int显式包装在NSNumber中。

使用OptionSet union方法合并下划线样式

我们可以将多个下划线样式组合成一个复合样式。在按位级别上,这是通过对表示两种样式的整数进行逻辑或来实现的。作为OptionSetNSUnderlineStyle提供了Swifty替代方案。 union(_:)上的NSUnderlineStyle方法以更简单的英语方式实现逻辑或。举个例子:
NSUnderlineStyle.double.union(.patternDot).rawValue

这段代码将生成一个Int,并翻转了相应的位,TextKit绘制了一个非常漂亮的虚线双下划线。当然,并不是所有的组合都能工作。 'NSAttributedString'可以接受任何内容,但是常识和TextKit引擎最终将决定。

10-08 06:08