使用appearance proxy定制控件的默认外观(详解)

控件的外观,受到tint color,background image, background color等属性的共同影响,通常要修改某个控件对象的外观,就去调用上面属性的相关setter方法(或者其他可以修改它们的方法)就可以了。但是,如果希望整个app中的控件都保持一致的风格,比如所有button的风格(指的是大小,背景图,形状等)都一样,那么一个一个去重复设置每个button的风格,就显得太麻烦了。如果可以给Button类设定一个默认外观,就方便多了。appearance proxy就可以实现。

对于导航栏,tabBarController等等管理多个视图控制器的控件,要对它们的全局外观进行修改,通常比较便捷的方法也是定制默认外观,也就是使用appearance proxy。下面就来详细介绍appearance proxy。

一、首先,要了解一个概念appearance proxy外观代理:

外观代理,它是一个管理可视化类(比如控件)的默认外观的对象。我们可以通过这个类的外观代理,来修改这个类的默认外观(与外观有关的属性的默认值),或者这个类在某种场合下的默认外观。

二、需要遵守两个协议

一个类要能够使用外观代理,需要遵守两个协议,一个是UIAppearance,一个是UIAppearanceContainer协议。

1. UIAppearance协议

该协议定义了4个方法,用于获取类的外观代理,分别对应4种外观代理。

2. UIAppearanceContainer协议

该协议定义了一个常量UI_APPEARANCE_SELECTOR,用来标识外观代理可以调用的方法。既然外观代理是用来管理类的默认外观的,那么能够被它调用的方法,或者说它需要调用的方法,往往就是类的某个外观特征的setter和getter方法。也就是说,为一个方法设定UI_APPEARANCE_SELECTOR标签,就表示这个方法可以为外观代理所用。当然,方法的格式是有规定的,基本格式和一般属性的setter和getter方法格式一样,在这个基础上可以增加更多的参数。参数的类型只能是NSInteger或NSUInteger,否则会报错。

三、外观代理的工作时间

官网上简洁的表述:

所有通过外观代理对默认外观进行的修改,只会在view layout time 时生效。在此之后,仍可以通过对象的属性和方法来覆盖此默认外观。

我的详细解释:

我们可以随时让外观代理修改默认外观,准确的理解是让外观代理记录好我们对默认外观的定制要求。但是外观代理只会在view layout time时工作一次,也就是让默认外观生效。在此之后,调用外观代理来修改默认外观,是不会即时生效的,换言之,必须要等到下次view layout time的时候才会让这个新定制的默认外观生效。什么时候是view layout time?从运行的效果来看,我暂且理解为加载window(或从其他window返回到本window)的时候,如果有更准确的理解,望赐教。

默认外观对类的所有的对象起作用(所谓默认,就是这个意思)。如果要在默认外观的基础上对某个对象的外观进行修改,就和平常一样,调用这个对象有关外观设置的方法即可。

四、外观代理的获取及使用

下面详细了解UIAppearance协议中定义的4种获取外观代理的方法,及其对应的4种外观代理:

1.全局外观代理

功能:代理中的Big Boss,它可以管理控件在任何情况下的默认外观。 
获取代理的方法:+ ( instancetype )appearance 
比如:要获取UINavigationBar的全局外观代理: 
UINavigation *appearanceProxy=[UINavigation appearance];

2.只负责指定场合的外观的外观代理

功能:管理控件被包含在指定的类(及其子类)中时的默认外观;管理控件被包含在指定的视图层级关系中时的默认外观。 
获取代理的方法:

+ ( instancetype )appearanceWhenContainedIn:(Class<UIAppearanceContainer>)ContainerClass, …     
  • 1

解释: 
这个方法的参数指定了某个类或者多个类。参数个数不定,最后一个参数必须是nil。 
例子: 
比如,获取 作用于“放在UIToolbar类中的UIBarButtonItem对象”的外观代理,这样写:

[UIBarButtonItem appearanceWhenContainedIn: [UIToolbar class],nil];
  • 1

注意: 
此时除了放在UIToolbar类中的UIBarButtonItem对象会受这个外观代理管理以外,放在UIToolbar的子类中的UIBarButtonItem对象也会受这个代理管理。 
如果要指定层级关系,则传入一个层级关系的对象。

上面说的方法从iOS 5.0开始启用,到iOS 9.0丢弃,iOS 9.0及以后用下面的方法替代:

+(instancetype)appearanceWhenContainedInInstancesOfClasses:(NSArray<Class <UIAppearanceContainer>> *)containerTypes
  • 1

比如,设置导航栏被放在UISplitViewController或者UITabBarController里面时的默认BarTintColor:

[[UINavigationBar appearanceWhenContainedInInstancesOfClasses:  @[[UISplitViewController class], [UITabBarController class]]] setBarTintColor:myColor];
  • 1

3.只负责控件在某种系统环境下的外观的外观代理

功能:管理类在某种系统环境下(比如横屏、竖屏等)的默认外观。系统环境由UITraitCollection对象来指定。(查看UITraitCollection Class Reference) 
获取代理的方法:

+ (instancetype)appearanceForTraitCollection:(UITraitCollection *)trait
  • 1

4.只负责控件在某种系统环境、某种场合下的外观的外观代理

功能:管理控件在某种系统环境、某种场合下的默认外观 
获取代理的方法:

+ (instancetype)appearanceForTraitCollection:(UITraitCollection *)trait  whenContainedIn:(Class<UIAppearanceContainer>)ContainerClass
  • 1

以上方法从5.0开始启用,在iOS 9.0被丢弃,iOS 9.0及以后用下面这个方法替代:

+ (instancetype)appearanceForTraitCollection:(UITraitCollection *)trait whenContainedInInstancesOfClasses:(NSArray<Class <UIAppearanceContainer>> *)containerTypes
时间: 2024-10-20 08:02:02

使用appearance proxy定制控件的默认外观(详解)的相关文章

UIAppearance定制控件的默认外观

一,概述 控件的外观,受到tint color,background image, background color等属性的共同影响,通常要修改某个控件对象的外观,就去调用上面属性的相关setter方法(或者其他可以修改它们的方法)就可以了.但是,如果希望整个app中的控件都保持一致的风格,比如所有button的风格(指的是大小,背景图,形状等)都一样,那么一个一个去重复设置每个button的风格,就显得太麻烦了.如果可以给Button类设定一个默认外观,就方便多了.appearance pro

OpenLayers 之 控件(control)详解

每一个地图应用都应该有一些工具方便用户控制地图的行为,比如缩放,全屏,坐标控件等等,在 OpenLayers 中怎么添加这些工具呢?下面我给大家介绍一下 OpenLayers 中包含的控件种类,并介绍其使用方法.对控件的定制化,和对 OpenLayers 增加控件和优化控件等超出了本文范围. 一.control 类 OpenLayers 中的控件是由 control 类定义的,这是一个虚基类,不负责实例化特定的控件,它的主要作用是让其他具体的种类的控件类实现继承.OpenLayers 中包含的控

第二章 控件架构与自定义控件详解 + ListView使用技巧 + Scroll分析

1.Android控件架构下图是UI界面架构图,每个Activity都有一个Window对象,通常是由PhoneWindow类来实现的.PhoneWindow将DecorView作为整个应用窗口的根View,DecorView将屏幕分成两部分:TitleView和ContentView.ContentView实际上是一个FrameLayout,里面容纳的就是我们在xml布局文件中定义的布局. 为什么调用requestWindowFeature()方法一定要在setContentView()方法调

Android 控件架构与自定义控件详解

架构: PhoneWindow 将一个 DecorView 设置为整个应用窗口的根 View,这里面所有 View 的监听事件,都通过 WindowManagerService 来接收.DecorView 分为 TitleView 和 ContentView,ContentView 是一个 ID 为 content 的 FrameLayout 在 onCreate() 方法中调用 setContentView() 方法后,ActivityManagerService 会回调onResume() 

Android控件架构与自定义控件详解(二)——自定义View

在自定义View时,我们通常会去重写onDraw()方法来绘制View的显示内容.如果该View还需要使用wrap_content属性,那么还必须重写onMeasure()方法.另外,通过自定义attrs属性,还可以设置新的属性配置值. 在View中通常有一些比较重要的回调方法. onFinishInflate():从XML加载组件后回调. onSizeChanged(;:组件大小改变时. onMeasure():回调该方法来进行测量. onLayout():回调该方法来确定显示的位置. onT

Android控件架构与自定义控件详解

基于 <android 群英传 >的读书笔记 View的测量-onMeasure() 测量的模式可以有以下三种: EXACTLY 即精确值模式,当我们将控件的layout_width属性或layout_height属性指定为具体参数值时,系统使用的就是EXACTLY AT_MOST 即最大值模式,当控件的layout_width属性或layout_hright属性是warp_content时,控件大小一般随着控件的子控件或内容的变化而变化,此时控件尺寸只要不超过父控件允许的尺寸即可 UNSPE

ListView(1)控件架构与ArrayAdapter详解

ListView是Android开发中比较常用的一个组件,它以列表的形式展示信息,并能根据信息的长度自适应显示.比如说我们手机里的通讯录就用到了ListView显示联系人信息.在大量的场合下,我们都需要使用这个控件.虽然在Android 5.0时代,RecyclerView在很多地方都在逐渐取代ListView,但ListView的使用范围依然非常的广泛.我们也不能跳过ListView直接去学习RecyclerView,对ListView的透彻理解是十分有必要的. 首先来看ListView在Vi

【React Native开发】React Native控件之WebView组件详解以及实例使用(22)

转载请标明出处: http://blog.csdn.net/developer_jiangqq/article/details/50676379 本文出自:[江清清的博客] (一)前言 [好消息]个人网站已经上线运行,后面博客以及技术干货等精彩文章会同步更新,请大家关注收藏:http://www.lcode.org 今天我们一起来看一下WebView组件讲解以及使用实例 刚创建的React Native技术交流群(282693535),欢迎各位大牛,React Native技术爱好者加入交流!同

定制控件背景颜色与背景位图

本文讲述如何定制控件的背景颜色和背景位图的技巧. 首先要说一下控件的绘制过程:当控件的某个区域需要重绘时,都会触发WM_ERASEBKGND和WM_PAINT消息.比如控件的某个区域被另一个程序的窗口挡住了,而后那个窗口又被移走了,这时控件被挡住的内容就需要重新绘制了. 第一步:系统向控件发送WM_ERASEBKGND消息以实现背景的擦除工作(有时不发送,比如用户可能调用InvalidateRect(),其参数却指定不擦除背景,这样就没有这个消息): 第二步:系统向控件的窗口过程发送WM_PAI