Подтвердить что ты не робот

UIAppearance не действует на UILabels, созданный программно

Мы расширили UILabel, чтобы иметь возможность применять стандартные шрифты и цвета для всех видов использования данного типа меток в наших приложениях. Например.

@interface UILabelHeadingBold : UILabel
@end

В нашем приложении AppDelegate мы применяем шрифты и цвета, подобные этому

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

При добавлении UILabel в наши XIB мы теперь можем выбрать класс типа UILabelHeadingBold, и он работает так, как ожидалось. Метка отображается с правильным шрифтом и цветом, как указано в нашем AppDelegate.

Однако, если мы создаем метку программно, например.

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

UILabel не получает ожидаемый шрифт/цвет. Мы должны вручную применить эти атрибуты.

Есть ли способ заставить UIAppearance вступить в силу для программно созданных элементов пользовательского интерфейса или работает только при использовании в XIB?

4b9b3361

Ответ 1

Из документации Apple:

Чтобы поддерживать настройку внешнего вида, класс должен соответствовать Протокол UIAppearanceContainer и соответствующие методы доступа должны быть помечены знаком UI_APPEARANCE_SELECTOR.

Например, в UINavigationBar.h, tintColor помечено UI_APPEARANCE_SELECTOR

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

Но в UILabel.h вы можете видеть, что свойства textColor и font не помечены с помощью UI_APPEARANCE_SELECTOR, но как-то он работает при добавлении в Interface Builder (в соответствии с документацией он вообще не должен работать).

Ответ 2

Простой хак, который работает для меня без проблем, - это создание категории с установщиком UIAppearance, который изменяет свойства UILabel.

Следуя соглашениям 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

Я все еще пытаюсь понять, почему оригинальный сеттер не работает.

Ответ 3

Решение

@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);
    }
}

Ответ 4

Обходной путь, который я использовал, состоит в том, чтобы вручную применить цвет из установленного внешнего вида:

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

Таким образом, вам не нужно ссылаться на что-то новое или явно определять цвет. Это также работает для контекстно-зависимой окраски:

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

Ответ 5

У меня была точно такая же проблема, но в Свифте. Пользовательский UILabel вид 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