Accoding to 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."
Therefore, I'm trying to set text attributes, which are later used to create a NSAttributedString
, to a property var titleTextAttributes: [String : AnyObject]?
in a UIView
subclass like this:
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(),
]
}
This is a snipped from my AppDelegate
.
Now, when trying to set ActionBarView.appearance().titleTextAttributes = [ ... ]
, I'm getting the following runtime error:
What's worth mentioning is that setting the attributes on UINavigationBar
works without any problems.
Going to UINavigationBar
's header file reveals this:
/* 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]?
Which is exactly the same definition of a property as in my ActionBarView
class:
class ActionBarView: UIView {
var titleTextAttributes: [String : AnyObject]?
// ...
}
So my question is: Is there anything I can do to implement a property with a dictionary of text attributes in my own UIView subclass that can be set via UIAppearance
proxy? Since using UI_APPEARANCE_SELECTOR
is not possible in Swift? And why is it working out-of-the-box for UIKit classes like UINavigationBar
? Is there some kind of black magic involved?
For appearance property just add dynamic keyword:
class ActionBarView: UIView {
dynamic var titleTextAttributes: [String : AnyObject] = [:]
// use ActionBarView.appearance().titleTextAttributes
}
and For appearance property accessor methods must be of the form:
func propertyForAxis1(axis1: IntegerType, axis2: IntegerType, axisN: IntegerType) -> PropertyType
func setProperty(property: PropertyType, forAxis1 axis1: IntegerType, axis2: IntegerType)
Based on this answer, marking the property titleTextAttributes
as dynamic
and backing it with another one as a storage solves the issue:
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
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With