自适应界面应该响应特征和大小改变。 在视图控制器级别,您可以使用特征对显示的内容和该内容的布局进行粗略确定。 例如,当在大小类之间更改时,您可以选择更改视图属性,显示或隐藏视图,或显示完全不同的视图集。 做出这些重大决定后,您可以使用大小更改来调整您的内容。
适应特征变化
特征为您提供了一种为不同环境不同地配置应用程序的方法,您可以使用它们对界面进行粗调。 使用特征进行的大部分更改可以直接在故事板文件中完成,但有些需要额外的代码。
配置您的故事板以处理不同大小类
Interface Builder使您可以轻松地将界面适应不同大小的类。 故事板编辑器包括支持以不同大小类配置显示您的界面,用于删除特定配置中的视图以及指定不同的布局约束。 您还可以创建针对不同大小类别提供不同图像的图片资源。 使用这些工具意味着您不必在运行时以编程方式进行相同的更改。 相反,UIKit会在当前大小类更改时自动更新您的界面。
图13-1显示了在Interface Builder中用于配置界面的工具。 大小类查看控件会更改您的界面的外观。 使用该控件来查看您的界面将如何查找给定的大小类。 对于单个视图,使用安装控件配置是否存在给定大小类配置的视图。 使用复选框左侧的加号(+)按钮添加新配置。
图13-1为不同大小类自定义界面
注意
已卸载的视图仍保留在视图层次结构中,可能会正常操作,但不会显示在屏幕上。
图片资源是存储应用程序图片资源的首选方式。 每个图片资源包含同一图片的多个版本,每个版本都针对特定配置进行设计。 除了为标准和Retina显示指定不同的图像,还可以为不同的水平和垂直尺寸类别指定不同的图像。 配置图像资源时,UIImageView对象会自动选择与当前大小类和分辨率相关联的图像。
图13-2显示了图像属性。 更改width和height属性会在目录中添加更多图像的插槽。 用图像填充这些插槽,以用于每个尺寸类组合。
图13-2为不同大小类别配置图像属性
更改子视图控制器的特征
默认情况下,子视图控制器继承其父视图控制器的特性。 对于像大小类的特征,可能没有意义每个孩子具有相同的特质作为其父。 例如,常规环境中的视图控制器可能想要向其一个或多个子项分配紧凑大小类以反映该子项的减少的空间量。 当实现容器视图控制器时,通过调用容器视图控制器的setOverrideTraitCollection:forChildViewController:方法来修改子的特征。
代码清单13-1显示了如何创建一组新特征并将它们与子视图控制器相关联。 您从父视图控制器执行此代码,只需要这样做一次。 覆盖的特征会保留在子代中,直到您再次更改它们或直到您从视图控制器层次结构中删除子代。
代码清单13-1更改子视图控制器的特征
UITraitCollection* horizTrait = [UITraitCollection
traitCollectionWithHorizontalSizeClass:UIUserInterfaceSizeClassRegular];
UITraitCollection* vertTrait = [UITraitCollection
traitCollectionWithVerticalSizeClass:UIUserInterfaceSizeClassCompact];
UITraitCollection* childTraits = [UITraitCollection
traitCollectionWithTraitsFromCollections:@[horizTrait, vertTrait]];
[self setOverrideTraitCollection:childTraits forChildViewController:self.childViewControllers[0]];
当父视图控制器的特性改变时,子级继承父级没有显式覆盖的任何特性。 例如,当父级的水平大小类从正常变为紧凑时,上例中的子级保留其常规水平大小类。 但是,如果displayScale 特征更改,则子代继承新值。
使呈现的视图控制器适应新样式
呈现的视图控制器在水平规则和紧凑环境之间自动适应。 当从水平规则环境转换到水平紧凑环境时,UIKit默认将内置表示风格更改为UIModalPresentationFullScreen。 对于自定义控制器样式,呈现控制器可以确定适应行为并相应地调整呈现。
对于某些应用程序,适应全屏样式可能会出现问题。 例如,弹出窗口通常通过在其边界外部敲击来解除,但是在弹出窗口覆盖整个屏幕的紧凑环境中这样做是不可能的,如图13-3所示。 当默认的适应风格不适当时,你可以告诉UIKit使用不同的风格或呈现更完全不同的视图控制器,更好地适合全屏风格。
图13-3在常规和紧凑环境中的弹出窗口
要更改呈现样式的默认自适应行为,请将委派分配给关联的呈现控制器。 您可以使用提供的视图控制器的presentationController属性访问呈现控制器。 在进行任何适应性相关的更改之前,呈现控制器会咨询您的委托对象。 代理可以返回与默认不同的呈现样式,并且它可以向呈现控制器提供要显示的替代视图控制器。
使用委托的adaptivePresentationStyleForPresentationController:方法来指定与默认不同的表示风格。 当转换到一个紧凑的环境,唯一支持的样式是两个全屏样式或UIModalPresentationNone。 返回UIModalPresentationNone告诉呈现控制器忽略紧凑环境并继续使用先前的呈现风格。 在弹出窗口的情况下,忽略更改会给所有设备上类似iPad的popover行为。 图13-4显示了默认的全屏自适应,没有适配,因此您可以比较生成的呈现。
图13-4更改所提供的视图控制器的自适应行为
要完全替换视图控制器,请实现委托的presentationController:viewControllerForAdaptivePresentationStyle:方法。 当适应于紧凑环境时,您可以使用该方法将导航控制器插入视图层次结构或加载专为较小空间设计的视图控制器。
实现自适应弹窗的提示
当从水平正则变为水平紧凑时,弹出框需要额外的修改。 水平紧凑的默认行为会将其更改为全屏演示。 因为弹出通常通过点击弹出框的边界以外被忽略,改变为全屏显示消除了消除弹出的主要技术。 您可以通过执行以下操作之一来补偿该行为:
- 将弹出的视图控制器推送到现有的导航堆栈。 当有父导航控制器可用时,关闭弹出并将其视图控制器推到导航堆栈上。
- 添加控件以在全屏显示时关闭弹窗。 您可以向弹窗的视图控制器添加控件,但更好的选择是使用presentationController:viewControllerForAdaptivePresentationStyle:方法交换导航控制器的popover。 使用导航控制器为您提供了模式界面和空间,以添加完成按钮或其他控件来关闭内容。
- 使用呈现控制器委派来消除任何适应性更改。 获取弹窗呈现控制器并分配一个委托给它实现adaptivePresentationStyleForPresentationController:方法。 从该方法返回UIModalPresentationNone会导致弹窗继续显示为弹窗。
响应大小更改
尺寸更改可能有多种原因,包括:
- 底层窗口的尺寸改变,通常是因为方向改变。
- 父视图控制器调整其子级之一。
- 呈现控制器改变其呈现的视图控制器的大小。
当大小更改发生时,UIKit通过正常布局过程自动更新可见视图控制器层次结构的大小和位置。 如果您使用“自动布局”限制指定视图的大小和位置,则您的应用会自动适应任何大小更改,并应在具有不同屏幕尺寸的设备上运行。
如果您的Auto Layout约束不足以实现所需的外观,您可以使用viewWillTransitionToSize:withTransitionCoordinator:方法更改布局。 您还可以使用该方法创建附加的动画,以与大小更改动画一起运行。 例如,在界面旋转期间,您可以使用转换协调器的targetTransform属性为接口的某些部分创建反向旋转矩阵。