何时可以开始使用通过UIAppearance设置的属性集?

10

我的视图类(继承自UIView)有一些自定义外观属性。我想根据这些属性自定义视图外观,但我不能在初始化程序内部执行此操作,因为使用[[MyClass appearance] setFoo:...]设置的值此时尚未生效:

@interface View : UIView
@property(strong) UIColor *someColor UI_APPEARANCE_SELECTOR;
@end

@implementation View
@synthesize someColor;

// Somewhere in other code before the initializer is called:
// [[View appearance] setSomeColor:[UIColor blackColor]];

- (id) initWithFrame: (CGRect) frame
{
    self = [super initWithFrame:frame];
    NSLog(@"%@", someColor); // nil
    return self;
}

@end

这些已经在layoutSubviews中设置了,但这不是执行视图定制的好时机,因为一些自定义可能会再次触发layoutSubviews,导致无限循环。

那么,执行自定义的好时机是什么?或者有没有一种方法来触发应用外观值的代码?


我认为一旦自定义类被分配,成员的属性就可以根据需要随时访问和更改,然后对象可以在代码中使用修改后的信息。 - Abhishek Singh
1
只是为了确保,我说的是通过外观代理(UIAppearance)设置的属性。这些值在初始化程序之后的某个地方设置。如果我在属性设置器上设置断点,我可以看到这些值是从 [CALayer layoutSublayers] 应用的。 - zoul
5个回答

2
一个可能的解决方法是直接从代理获取值:
- (id) initWithFrame: (CGRect) frame
{
    self = [super initWithFrame:frame];
    NSLog(@"%@", [[View appearance] someColor); // not nil
    return self;
}

当然,这会破坏根据视图容器变化外观的选项,而且通常很丑。我发现的第二个选项是在setter中执行自定义操作:
- (void) setSomeColor: (UIColor*) newColor
{
    someColor = newColor;
    // do whatever is needed
}

虽然我更希望有一个钩子在外观属性设置之后被调用。


请看我的回答;“hook”是UIView didMoveToSuperview:方法,我相信。 - TomSwift

1

为什么不等待一下呢?

- (void)willMoveToSuperview:(UIView *)newSuperview {
    [super willMoveToSuperview:newSuperview];

    if (newSuperview) {
        ... code here ...
    }
}

如果它给你带来了麻烦?


2
那是我的下一次尝试,但在那个时候值也没有被设置。 - zoul

1
注意:我使用的是Swift 2,不确定之前的Swift/Objective-C版本。但是我发现didMoveToSuperview()将不起作用。属性可以在layoutSubviews()中使用,但这不是做任何像这样的事情的好地方(因为它可能被调用多次)。我发现在视图的生命周期中访问这些属性的最佳位置是didMoveToWindow()。

1
我相信UIAppearance属性是在视图被添加到视图层次结构中时应用的。因此,您可以在UIView didMoveToSuperview中访问已设置的属性。

0

我认为viewDidLoad最好只用于一次性的事情。否则,就使用viewWillAppear。

编辑:

如果你想在视图中完成而不是在控制器中完成,那么我会创建一个自定义的视图初始化方法,类似于:

-(id) initWithFrame:(CGRect) frame andAppearanceColor:(UIColor)theColor;

因此在创建视图时将颜色传递进去。


这些是控制器方法,我更愿意在视图中处理它。此外,在这些调用期间很可能尚未设置值。 - zoul
将颜色传递到初始化程序中也不是一个选项,因为还有更多的外观属性需要设置,而且初始化程序在控制器无法控制的地方被调用。可以说,外观代理 API 的整个目的就是摆脱手动设置值的烦恼。 - zoul
我明白你的意思。也许你可以创建一个方法来设置外观属性,并在 NSNotification 响应中调用它(当指定外观属性时发送 NSNotification)。 - ader
当通过[[View appearance] setSomeColor:…]设置外观属性时,View的实例尚不存在,因此很遗憾这也不是一个选项。 - zoul

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接