我在 iOS 应用程序中使用自定义字体,并设置了如下字体:
private enum MalloryProWeight: String {
case book = "MalloryMPCompact-Book"
case medium = "MalloryMPCompact-Medium"
case bold = "MalloryMPCompact-Bold"}
extension UIFont {
enum Caption {
private static var bookFont: UIFont {
UIFont(name: MalloryProWeight.book.rawValue, size: 1)!
}
private static var mediumFont: UIFont {
UIFont(name: MalloryProWeight.medium.rawValue, size: 1)!
}
private static var boldFont: UIFont {
UIFont(name: MalloryProWeight.bold.rawValue, size: 1)!
}
static var book: UIFont {
return bookFont.withSize(10)
}
static var medium: UIFont {
mediumFont.withSize(10)
}
static var bold: UIFont {
boldFont.withSize(10)
}
}
这样在调用站点我可以执行以下操作:
UIFont.Caption.bold
这很有效;我有一个 NSAttributed 扩展,它接受 UIFont 和颜色并返回一个属性字符串 = 所以它非常适合。
但是,我现在需要在每种字体上设置 LetterSpacing 和 LineHeight。
我不想去更新 NSAttributed 扩展来获取这些值来设置它们 - 我理想地希望它们可以从 UIFont 访问
所以,我尝试子类化 UIFont 以向其中添加我自己的属性 - 就像这样:
class MrDMyCustomFontFont: UIFont {
var letterSpacing: Double?
}
像这样使用它
private static var boldFont: UIFont {
MrDMyCustomFontFont(name: MalloryProWeight.bold.rawValue, size: 1)!
}
但是编译器会提示,我不确定如何解决它:
Argument passed to call that takes no arguments
所以我的问题分为两部分:
- 如何在 UIFont 上添加我自己的自定义属性(并在每个实例的基础上设置它)
- 否则我如何正确子类化 UIFont 以便我可以在那里添加我自己的属性?
谢谢!
最佳答案
您无法子类化 UIFont,因为它通过 UICTFont 桥接到 CTFont。这就是为什么 init
方法在 header 中被标记为“未继承”。这不是一堂普通的类(class)。
您可以轻松地向 UIFont 添加新属性,但它不会按照您希望的方式工作。这正是您所要求的:每个实例。但它不会被复制,因此从 boldFont.withSize(10)
返回的实例不会具有与 boldFont
相同的值。如果您想要代码,请按以下步骤操作:
private var letterSpacingKey: String? = nil
extension UIFont {
var letterSpacing: Double? {
get {
(objc_getAssociatedObject(self, &letterSpacingKey) as? NSNumber)?.doubleValue
}
set {
objc_setAssociatedObject(self, &letterSpacingKey, newValue.map(NSNumber.init(value:)),
.OBJC_ASSOCIATION_RETAIN)
}
}
}
然后你就可以设置它:
let font = UIFont.boldSystemFont(ofSize: 1)
font.letterSpacing = 1
print(font.letterSpacing) // Optional(1)
但是只要创建派生字体,您就会丢失它:
let newFont = font.withSize(10)
print(newFont.letterSpacing) // nil
所以我认为你不想要这样。
但其中大部分内容并没有真正意义。你会用这些属性做什么? “字母间距”不是字体特征;而是字体特征。这是布局/风格特征。谎报字体的高度也可能是错误的工具;配置通常也是段落特征。
您可能想要的是一个“样式”,它可以跟踪所有有问题的内容(字体、间距、段落样式等),并且可以应用于 AttributedString。幸运的是,iOS 15+ 中已经存在:AttributeContainer。在 iOS 15 之前,您只能使用 [NSAttributedString.Key: Any]
。
然后,您可以直接合并容器/字典(这正是它的设计工作方式),而不是使用 (NS)AttributedString 扩展来合并字体。
extension AttributeContainer {
enum Caption {
private static var boldAttributes: AttributeContainer {
var container = AttributeContainer()
container.font = UIFont(name: MalloryProWeight.bold.rawValue, size: 1)!
container.expansion = 1
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = 1.5
container.paragraphStyle = paragraphStyle
return container
}
static var bold: AttributeContainer {
var attributes = boldAttributes
attributes.font = boldAttributes.font.withsize(10)
return attributes
}
}
}
关于swift - 无法子类化 UIFont,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72972953/