【问题标题】:Set text attributes via UIAppearance in a custom UIView subclass in Swift在 Swift 的自定义 UIView 子类中通过 UIAppearance 设置文本属性
【发布时间】:2016-11-25 07:44:50
【问题描述】:

根据NSHipster 的说法,“让自定义 UI 类符合 UIAppearance 不仅是最佳实践,而且它表明在其实施中投入了一定程度的关注。”

因此,我尝试将文本属性设置为 UIView 子类中的属性 var titleTextAttributes: [String : AnyObject]?,如下所示:

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 ActionBarView: UIView {

    var titleTextAttributes: [String : AnyObject]?

    // ...
}

所以我的问题是:我可以做些什么来在我自己的 UIView 子类中实现一个带有文本属性字典的属性,该子类可以通过UIAppearance 代理设置? 既然在 Swift 中无法使用 UI_APPEARANCE_SELECTOR 为什么它对像 UINavigationBar 这样的 UIKit 类开箱即用?是否涉及某种黑魔法?

【问题讨论】:

  • 似乎将我的属性 titleTextAttributes 标记为 dynamic 并用另一个作为存储来支持它可以解决此问题:stackoverflow.com/a/28734970/1161723
  • 好吧,我猜你告诉我了!对于那个很抱歉。所以这个特性必须通过某种调配(比如 KVO,它也需要dynamic)来工作。

标签: ios swift uikit nsattributedstring uiappearance


【解决方案1】:

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

class ActionBarView: UIView {

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

    // use ActionBarView.appearance().titleTextAttributes 
}

对于外观属性访问器方法必须是form:

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

【讨论】:

  • 可以实现对dynamic 不敏感的样式,并能够使用嵌套对象的属性(如view.layer.cornerRadius)。有兴趣的可以看看StyleSheet
【解决方案2】:

基于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
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-10-25
    • 1970-01-01
    • 2011-01-14
    • 1970-01-01
    • 2019-05-29
    • 2015-11-27
    • 2021-03-16
    相关资源
    最近更新 更多