iOS 5: 想了解UIAppearance

50

在2011年的技术演讲中,我看到了一场关于新的UIAppearance 协议的演讲。目前还没有太多的文档资料。我将简要总结我记得的内容,以解释我的问题来自何处:


关于UIAppearance

到目前为止,你必须在所有应用程序视图控制器中自定义每个导航栏(工具栏等)属性。有了新的外观属性,您只需在一个地方为应用程序中所有导航栏进行设置即可。例如:如果您想自定义导航栏背景图像,则可以像这样处理:

[[UINavigationBar appearance] setBackgroundImage:
   [UIImage imageNamed:@"MyImageName"] forBarMetrics:UIBarMetricsDefault]; 

这将设置应用程序中所有导航栏的背景图像。 使用barMetrics,您可以指定是否希望在横向模式下也使用该图像。

如果您只想指定在某些视图控制器中应用外观,则文档中还有一种方法可以通过指定对象所在的位置来控制:

[[UIBarButtonItem appearanceWhenContainedIn:
    [ABPeoplePickerNavigationController class], nil] setTintColor:myNavBarColor];

值得一提的是,如果你有单独的自定义实例与外观设置不同,这些实例将不受外观代理的影响。


一些问题:

a)如何知道类的哪些属性适用于外观属性?例如,由于UITableView符合UIAppearance协议,我想我可以做一些类似于

[[UITableView appearance] setBackgroundColor:mytableViewColor];

我想要操作所有表视图的背景颜色,但是我做不到!

b) 是否有一个可以通过外观属性进行操作的所有类的列表?

c) 外观定制被调用的时间点是什么时候?我希望在运行时通过外观属性进行更改,但不幸的是这些更改没有生效。


6
我在这里(https://dev59.com/I2ox5IYBdhLWcg3wHAwA)代表你提出了问题b)并提供了答案。我这样做是因为我觉得你的问题标题太笼统了,没有人能找到我费力编制的列表。 - Emile Cormier
3个回答

36

a) 我如何知道一个类的哪些实例可以使用外观属性?例如,由于UITableView符合UIAppearance协议,我想我可以这样做:

您可以查看该类的头文件(以及所有超类的头文件)。任何具有UI_APPEARANCE_SELECTOR标记的方法都可以与UIAppearance代理一起使用。

[[UITableView appearance] setBackgroundColor:mytableViewColor];

backgroundColor属性在UIView.h中未使用UI_APPEARANCE_SELECTOR修饰,因此在外观代理中技术上不支持它。尽管它可能会起作用,但(由于缺乏方法修饰)不能保证。

UIAppearance Protocol Reference中可以得知:

要支持外观自定义,类必须符合UIAppearanceContainer协议,并且相关的访问器方法必须标记为UI_APPEARANCE_SELECTOR

(注意:“并且相关的访问器方法必须标记为...” [强调已添加])


b) 是否有所有可以使用外观属性进行操作的属性列表?

是否有单个页面显示每个使用外观代理的setter?我不知道有没有这样的页面,也没有办法在运行时构建列表。


c) 外观自定义在什么时候被调用?我希望通过外观属性在运行时进行更改,但不幸的是更改没有生效。

您可以在执行的任何时候使用外观代理。 更改将在下一次调用那些视图的-layoutSubviews方法时应用于受影响的视图。


3
现在有一份支持UIAppearance的类的列表,您可以在这里查看。也许您需要更新您的回答。 - Moshe
1
我发现更改在下一次-layoutSubviews应用在下一个运行循环中才生效。还有其他人也遇到过这个问题吗? - Adam Ritenauer

3

UIAppearance是记录在每个类的头文件中的。在里面查找标记为UI_APPEARANCE_SELECTOR的方法,这些是您可以通过外观代理调用的方法。我不知道头文件之外是否有列表。

外观自定义会立即在代理传递后以及每次构造新对象时被调用。但是,只有那些标记有UI_APPEARANCE_SELECTOR的方法才能起作用。


“通过代理之后”是什么意思?我尝试在按下按钮后更改外观,但没有实现更改。在进入另一个视图并返回后,更改已应用。因此,我开始相信更改是在视图层次结构更改或调用布局方法时完成的。 - d.ennis

1

a: 以下行

 [[UITableView appearance] setBackgroundColor:[UIColor blueColor]];

将每个表视图都变成蓝色!在 iOS 5 模拟器上测试过。

b: UIAppearance 应该适用于 UIView 上的每个属性。所有 UIView 的子类都符合 UIAppearance Protocol

c: 我认为大多数人会创建一个类或方法来自定义外观,并在以下位置调用它:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

例如:[ApplicationAppearance setApplicationSchemaTo:ASchemaBlue];

编辑:

例如,UIBarButtonItem 定义了这些方法:

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

来自 UIAppearanceContainer Protocol Reference

UIBarButtonItem Class Reference 中定义了 tintColor。

@property(nonatomic, retain) UIColor *tintColor 但在UIBarButtonItem.h中被定义为:
@property(nonatomic,retain) UIColor *tintColor __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_5_0) UI_APPEARANCE_SELECTOR;

我认为文档不是最新的。


4
我不建议在这个系统中使用setBackgroundColor。文档中没有将其标记为UI_APPEARANCE_SELECTOR,因此它可能随时出现问题。请注意。 - Joshua Weinberg
我认为文档没有更新。我会编辑并解释原因。 - Alex Terente
在UITableView中,是的,您是正确的,而在UIView中没有UI_APPEARANCE_SELECTOR。 - Alex Terente
这很奇怪,对我不起作用。使用这行代码时,我只能在调用它的表视图中得到蓝色的背景颜色。 - d.ennis
不,我能在调用application:didFinishLaunchingWithOptions:之后通过将语句放置在运行时呈现的不同视图中来更改外观。释放此视图后,我看到了在每个其他视图中通过外观所做的更改。 - d.ennis
这就是它应该做的事情。要更改应用程序中的所有类,请使用[[UIBarButtonItem appearance] setTintColor:myNavBarColor]; 要仅更改一个类的外观,请使用[[UIBarButtonItem appearanceWhenContainedIn:[yourCustomClass class],nil] setTintColor:myNavBarColor]; - Alex Terente

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