UIAppearance 未对以编程方式创建的 UILabel 生效

Posted

技术标签:

【中文标题】UIAppearance 未对以编程方式创建的 UILabel 生效【英文标题】:UIAppearance not taking effect on UILabels created programmatically 【发布时间】:2012-07-03 17:39:01 【问题描述】:

我们对 UILabel 进行了扩展,以便能够在我们的应用程序中为给定标签类型的所有用途应用标准字体和颜色。例如。

@interface UILabelHeadingBold : UILabel
@end

在我们的 AppDelegate 中,我们像这样应用字体和颜色

[[UILabelHeadingBold appearance] setTextColor:<some color>];
[[UILabelHeadingBold appearance] setFont:<some font>];

当在我们的 XIB 中添加 UILabel 时,我们现在可以选择 UILabelHeadingBold 类型的类,它可以按预期工作。标签以正确的字体和颜色显示,如我们的 AppDelegate 中所指定。

但是,如果我们以编程方式创建标签,例如。

UILabelHeadingBold *headingLabel = [[UILabelHeadingBold alloc] initWithFrame:CGRectMake(10, 10, 100, 30)];
[self.mainView addSubview:headingLabel];

UILabel 未应用预期的字体/颜色。我们必须手动应用这些属性。

有没有办法让 UIAppearance 对以编程方式创建的 UI 元素生效,还是仅在 XIB 中使用时才有效?

【问题讨论】:

【参考方案1】:

来自 Apple 文档:

要支持外观定制,类必须符合 UIAppearanceContainer 协议和相关的访问器方法必须是 用 UI_APPEARANCE_SELECTOR 标记。

例如在UINavigationBar.h中,tintColor标记为UI_APPEARANCE_SELECTOR

@property(nonatomic,retain) UIColor *tintColor UI_APPEARANCE_SELECTOR;

但在 UILabel.h 中,您可以看到 textColorfont 属性没有用 UI_APPEARANCE_SELECTOR 标记,但在 Interface Builder 中添加时它以某种方式工作(按照文档说明它根本不应该工作)。

【讨论】:

确实有时也适用于在代码中创建的 UILabel,但结果不一致,ios 5 之间的行为也不同,嗯,你知道的。所以就不要用UIAppearance自定义UILabels +1 的信息,我不是唯一一个得到不一致结果的人(我花了几个小时编码,直到我找到你的评论)。 +1 为 robert.wijas 解决方案 - 我现在使用 - 一切都很好。【参考方案2】:

对我来说没有问题的简单技巧是使用修改 UILabel 属性的 UIAppearance 设置器创建一个类别。

我按照 UIAppearance 约定创建了一个方法:

- (void)setTextAttributes:(NSDictionary *)numberTextAttributes;

    UIFont *font = [numberTextAttributes objectForKey:UITextAttributeFont];
    if (font) 
        self.font = font;
    
    UIColor *textColor = [numberTextAttributes objectForKey:UITextAttributeTextColor];
    if (textColor) 
        self.textColor = textColor;
    
    UIColor *textShadowColor = [numberTextAttributes objectForKey:UITextAttributeTextShadowColor];
    if (textShadowColor) 
        self.shadowColor = textShadowColor;
    
    NSValue *shadowOffsetValue = [numberTextAttributes objectForKey:UITextAttributeTextShadowOffset];
    if (shadowOffsetValue) 
        UIOffset shadowOffset = [shadowOffsetValue UIOffsetValue];
        self.shadowOffset = CGSizeMake(shadowOffset.horizontal, shadowOffset.vertical);
    

在 UILabel 类别中:

@interface UILabel (UISS)

- (void)setTextAttributes:(NSDictionary *)numberTextAttributes UI_APPEARANCE_SELECTOR;

@end

我仍在试图弄清楚为什么原来的 setter 不起作用。

【讨论】:

我们在子类中创建与外观代理一起使用的自定义属性。例如。一个“titleLabelFont”属性来包装 UIButton 的 titleLabel.font 属性。它也适用于其他属性,例如阴影。 @robert +1 非常好的解决方案。花了我几个小时编码,直到我找到你的答案。感谢那。现在,一切正常(而且简单)。 很好的解决方案,这也适用于其他视图,例如用于设置 titleLabel 字体的 UIButton,因为 Apple 已弃用 setFont: 方法。 是的,但在其他一些 UILabel 之后我无法更改文本颜色【参考方案3】:

我遇到了同样的问题,但在 Swift 中。如果从情节提要添加自定义UILabel 的外观将起作用,但如果从代码添加则不会。

这是我在 Swift 中找到的一个对我有用的解决方案:

class MyLabel: UILabel  

extension UILabel 
    @objc dynamic var customFont: UIFont! 
        get  return self.font 
        set  self.font = newValue 
    

    @objc dynamic var customColor: UIColor! 
        get  return self.textColor 
        set   self.textColor = newValue 
    

然后在您配置应用外观的位置添加这些行:

MyLabel.appearance().customFont = UIFont.systemFont(ofSize: 20)
MyLabel.appearance().customColor = UIColor.magenta

【讨论】:

我已经为这个问题苦苦挣扎了好几个小时。这是一个非常快速且有效的解决方案!【参考方案4】:

@robert.wijas 解决方案效果很好!

对于 iOS 7 及更高版本,我必须更新密钥,因为他使用的密钥已被 7+ 弃用:

- (void)setTextAttributes:(NSDictionary *)numberTextAttributes;

    UIFont *font = [numberTextAttributes objectForKey:NSFontAttributeName];
    if (font) 
        self.font = font;
    
    UIColor *textColor = [numberTextAttributes objectForKey:NSForegroundColorAttributeName];
    if (textColor) 
        self.textColor = textColor;
    
    UIColor *textShadowColor = [numberTextAttributes objectForKey:NSShadowAttributeName];
    if (textShadowColor) 
        self.shadowColor = textShadowColor;
    
    NSValue *shadowOffsetValue = [numberTextAttributes objectForKey:NSShadowAttributeName];
    if (shadowOffsetValue) 
        UIOffset shadowOffset = [shadowOffsetValue UIOffsetValue];
        self.shadowOffset = CGSizeMake(shadowOffset.horizontal, shadowOffset.vertical);
    

【讨论】:

请注意,您没有正确处理 NSShadowAttributeName 属性;它的值是 NSShadow。【参考方案5】:

我使用的一种解决方法是从设置的外观手动应用颜色:

let label = UILabel()
label.textColor = UILabel.appearance().textColor

这样你就不需要引用任何新的东西,或者明确定义颜色。这也适用于特定于上下文的着色:

label.textColor = UILabel.appearance(whenContainedInInstancesOf:[MyView.self]).textColor

【讨论】:

以上是关于UIAppearance 未对以编程方式创建的 UILabel 生效的主要内容,如果未能解决你的问题,请参考以下文章

以编程方式清理 UI 的实现

UIAppearance

如何对以第一个字符开头的字符串数组进行排序?

如何在MonoTouch中为继承的视图创建UIAppearance代理?

如何从 UILabel 中删除 UIAppearance 设置?

使用 UIAppearance 代理设置 UILabel 样式