在 Swift 的自定义 UIView 子类中通过 UIAppearance 设置文本属性

Set text attributes via UIAppearance in a custom UIView subclass in Swift

根据NSHipster、"having custom UI classes conform to UIAppearance is not only a best-practice, but it demonstrates a certain level of care being put into its implementation."

因此,我正在尝试将稍后用于创建 NSAttributedString 的文本属性设置为 UIView 子属性 var titleTextAttributes: [String : AnyObject]? class 像这样:

func applyAppearance() {

    UINavigationBar.appearance().translucent = true
    UINavigationBar.appearance().tintColor = UIColor(named: .NavBarTextColor)
    UINavigationBar.appearance().barTintColor = UIColor(named: .NavBarBlue)
    UINavigationBar.appearance().titleTextAttributes = [
        NSForegroundColorAttributeName: UIColor(named: .NavBarTextColor),
        NSFontAttributeName: UIFont.navBarTitleFont()!
    ]

    ActionBarView.appearance().backgroundColor = UIColor(white: 1, alpha: 0.15)
    ActionBarView.appearance().titleTextAttributes = [
        NSKernAttributeName: 1.29,
        NSFontAttributeName: UIFont.buttonFont()!,
        NSForegroundColorAttributeName: UIColor.whiteColor(),
    ]
}

这是从我的 AppDelegate 中截取的。

现在,在尝试设置 ActionBarView.appearance().titleTextAttributes = [ ... ] 时,我收到以下运行时错误:

值得一提的是,在 UINavigationBar 上设置属性没有任何问题。

转到 UINavigationBar 的头文件显示:

/* You may specify the font, text color, and shadow properties for the title in the text attributes dictionary, using the keys found in NSAttributedString.h.
 */
@available(iOS 5.0, *)
public var titleTextAttributes: [String : AnyObject]?

属性 的定义与我的 ActionBarView class:

完全相同
class ActionBarView: UIView {

    var titleTextAttributes: [String : AnyObject]?

    // ...
}

所以我的问题是:在我自己的 UIView subclass 中可以通过 UIAppearance 设置文本属性字典,我可以做些什么来实现 属性代理? 既然在 Swift 中无法使用 UI_APPEARANCE_SELECTOR 为什么它可以开箱即用地用于 UIKit classes,例如 UINavigationBar?是否涉及某种黑魔法?

基于this answer,将属性 titleTextAttributes标记为dynamic并用另一个作为存储支持它解决了问题:

class ActionBarView: UIView {

    /// UIAppearance compatible property
    dynamic var titleTextAttributes: [String : AnyObject]? { // UI_APPEARANCE_SELECTOR
        get { return self._titleTextAttributes }
        set { self._titleTextAttributes = newValue }
    }

    private var _titleTextAttributes: [String : AnyObject]?

    // ... use `self.titleTextAttributes` in the implementation
}

外观属性只需添加动态关键字:

class ActionBarView: UIView {

    dynamic var titleTextAttributes: [String : AnyObject] = [:]

    // use ActionBarView.appearance().titleTextAttributes 
}

and For appearance 属性 访问器方法必须属于 form:

func propertyForAxis1(axis1: IntegerType, axis2: IntegerType, axisN: IntegerType) -> PropertyType
func setProperty(property: PropertyType, forAxis1 axis1: IntegerType, axis2: IntegerType)