ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
[TOC=5] * * * * * >原文链接 :[Building an Adaptive Interface](https://developer.apple.com/library/content/featuredarticles/ViewControllerPGforiPhoneOS/BuildinganAdaptiveInterface.html#//apple_ref/doc/uid/TP40007457-CH32-SW1) 自适应界面应该对特征和 Size Class 的变化做出反应。在视图控制器级别,可以使用特征对显示的内容和该内容的布局进行粗略确定。例如,在 Size Class 之间切换时,可以选择更改视图属性,显示或隐藏视图,或者显示完全不同的视图集。做出这些重大决定之后,可以使用 Size Class 更改来微调内容。 ### 第一节 适应特征变化 特征使您可以针对不同环境对应用程序进行不同的配置,并使用它们对界面进行粗略调整。 对特征所作的大部分改变可以直接在故事板文件中完成,但有些需要额外的代码。 #### 1.1 配置故事板处理不同 Size Class Interface Builder 可以轻松地将界面调整到适应不同的 Size Class 。故事板编辑器支持在不同 Size Class 配置中显示界面,在特定配置中删除视图,以及指定不同的布局约束。还可以创建为不同 Size Class 提供不同图像的图像资源。使用这些工具意味着不必在运行时以编程方式进行相同的更改。相反,UIKit 会在当前 Size Class 更改时自动更新界面。 图 13-1 显示了用于在 Interface Builder 中配置界面的工具。Size Class 查看控件改变了界面的外观。使用该控件来查看界面将如何查找给定的 Size Class。对于单个视图,请使用安装控件来配置对于给定的 Size Class 配置是否存在视图。使用复选框左侧的加号(+)按钮添加新的配置。 ###### 图 13-1 为不同 Size Class 定制界面 ![](https://developer.apple.com/library/content/featuredarticles/ViewControllerPGforiPhoneOS/Art/size_class_ib_setting_2x.png) > 注意: 卸载视图保留在您的视图层次结构中,并且可以正常操作,但不会显示在屏幕上。 图片资源是存储应用的图片的首选方式。每个图像资源包含同一图像的多个版本,每个版本都为特定的配置而设计。除了为标准和视网膜显示指定不同的图像之外,还可以为不同的水平和垂直 Size Class 指定不同的图像。使用图像资源进行配置时,[UIImageView](https://developer.apple.com/documentation/uikit/uiimageview) 对象将自动选择与当前 Size Class 和分辨率关联的图像。 图 13-2 显示了图像资源属性。在目录中更改宽度和高度属性添加更多图像插槽。用图像填充这些插槽以用于每个 Size Class 组合。 ###### 图13-2 为不同 Size Class 配置图像资产 ![](https://developer.apple.com/library/content/featuredarticles/ViewControllerPGforiPhoneOS/Art/size_class_image_asset_2x.png) #### 1.2 更改子视图控制器的特征 子视图控制器默认继承父视图控制器的特征。对于尺寸类别这样的特征来说,每个子节点与父节点具有相同的特征是没有意义的。例如,常规环境中的视图控制器可能希望为其一个或多个子节点分配紧凑 Size Class 以反映该子节点的空间量减少。在实现容器视图控制器时,通过调用容器视图控制器的 [setOverrideTraitCollection:forChildViewController:](https://developer.apple.com/documentation/uikit/uiviewcontroller/1621406-setoverridetraitcollection) 方法来修改子节点特征。 清单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]]; ~~~ 当父视图控制器的特征发生变化时,子节点继承任何未被父代明确覆盖的特征。 例如,当父级的水平 Size Class 从常规变为紧凑时,上例中的子节点保留其常规水平 Size Class 。 但是,如果 [displayScale](https://developer.apple.com/documentation/uikit/uitraitcollection/1623519-displayscale) 特征发生更改,则子节点继承新值。 #### 1.3 将呈现的视图控制器调整为新的样式 被呈现视图控制器自动适应水平常规和紧凑的环境。从水平常规环境转换到水平紧凑环境时,UIKit 默认将内置呈现样式更改为 [UIModalPresentationFullScreen](https://developer.apple.com/documentation/uikit/uimodalpresentationstyle/1621361-fullscreen) 。对于自定义呈现样式,呈现控制器可以决定适应行为并相应地调整呈现效果。 对于一些应用来说,适应全屏模式可能会带来问题。例如,弹窗通常通过在其边界以外的地方点击来关闭,但是在弹出窗口覆盖整个屏幕的紧凑环境中这样做是不可能的,如图 13-3 所示。当默认的适应风格不合适时,可以告诉UIKit使用不同的样式,或者呈现完全不同的但是更适合于全屏样式视图控制器。 ###### 图 13-3 常规和紧凑环境中的弹出窗口 ![](https://developer.apple.com/library/content/featuredarticles/ViewControllerPGforiPhoneOS/Art/VCPG_popover-in-regular-and-compact-views_13_3_2x.png) 要更改呈现样式的默认自适应行为,请将代理赋值给关联的呈现控制器。可以使用被呈现视图控制器的 [presentationController](https://developer.apple.com/documentation/uikit/uiviewcontroller/1621426-presentationcontroller) 属性访问呈现控制器。在进行任何与适应性相关的更改之前,呈现控制器会访问代理对象。代理可以返回与默认不同的演呈现样式,并且可以向呈现控制器提供可选的视图控制器进行显示。 使用代理的 adaptivePresentationStyleForPresentationController: 方法指定与默认不同的演呈现样式。转换到紧凑型环境时,唯一受支持的样式是两个全屏样式或UIModalPresentationNone。返回 UIModalPresentationNone 会通知呈现控制器忽略紧凑环境,并继续使用先前的呈现样式。在弹出窗口的情况下,忽略更改会为所有设备提供与 iPad 类似的弹出窗口行为。 图 13-4 显示了默认的全屏适应和非全屏,并且并排显示,因此可以比较呈现结果。 ###### 图片 13-4 更改被呈现视图控制器的自适应行为 ![](https://developer.apple.com/library/content/featuredarticles/ViewControllerPGforiPhoneOS/Art/VCPG_changing-adaptive-behavior-for-presented-view-controller_13-4_2x.png) 要完全替换视图控制器,请实现委托的 [presentationController:viewControllerForAdaptivePresentationStyle:](https://developer.apple.com/documentation/uikit/uiadaptivepresentationcontrollerdelegate/1618326-presentationcontroller) 方法。在适应紧凑的环境时,可以使用该方法将导航控制器插入到视图层次结构中,或者加载专为较小空间设计的视图控制器。 #### 1.4 实现自适应弹窗的技巧 从水平常规变为水平紧凑时,窗口需要额外的修改。 水平紧凑的默认行为将它变成全呈现。因为弹出式窗口通常是通过在弹出式界面之外点击来关闭的,所以转换到全屏呈现则消除了关闭弹出窗口的操作。 可以通过执行以下操作之一来弥补该行为: * **将弹窗的视图控制器推到现有的导航堆栈上**。 当有导航控制器可用时,关闭弹出窗口并将其视图控制器推入导航堆栈。 * **添加控件以在全屏显示时关闭弹出窗口**。可以将控件添加到弹出窗口的视图控制器,但更好的选择是使用 [presentationController:viewControllerForAdaptivePresentationStyle:](https://developer.apple.com/documentation/uikit/uiadaptivepresentationcontrollerdelegate/1618326-presentationcontroller) 方法将导航控制器的弹出窗口替换掉。使用导航控制器提供一个模板界面和空间来添加一个完成按钮或其他控件来关闭内容。 * **使用呈现控制器代理来消除任何适应性更改**。获取弹窗视图控制器并为其赋值一个实现 [adaptivePresentationStyleForPresentationController:](https://developer.apple.com/documentation/uikit/uiadaptivepresentationcontrollerdelegate/1618343-adaptivepresentationstyleforpres)方法的代理。从该方法返回 [UIModalPresentationNone](https://developer.apple.com/documentation/uikit/uimodalpresentationstyle/1621386-none) 会导致弹出窗口继续显示为弹出窗口。有关更多信息,请参阅 [Adapting Presented View Controllers to a New Style](https://developer.apple.com/library/content/featuredarticles/ViewControllerPGforiPhoneOS/BuildinganAdaptiveInterface.html#//apple_ref/doc/uid/TP40007457-CH32-SW6)。 ### 第二节 响应 Size 变化 由于许多原因,可能会发生 Size 变化,包括以下内容: * 底层窗口的 Size 变化,通常是因为方向变化。 * 父视图控制器调整它的一个子节点。 * 一个呈现控制器改变被呈现视图控制器的 Size 。 当 Size 发生变化时,UIKit 通过正常的布局过程自动更新可见视图控制器层次结构的大小和位置。如果您使用“自动布局”约束来指定视图的大小和位置,则应用程序会自动适应任何大小的更改,并且应该在不同屏幕大小的设备上运行。 如果自动布局约束不足以实现所需外观,则可以使用 [viewWillTransitionToSize:withTransitionCoordinator:](https://developer.apple.com/documentation/uikit/uicontentcontainer/1621466-viewwilltransitiontosize) 方法更改布局。还可以使用该方法创建额外的动画,以便与 Size 更改动画一起运行。例如,在界面旋转过程中,可以使用转换协调器的 [targetTransform](https://developer.apple.com/documentation/uikit/uiviewcontrollertransitioncoordinatorcontext/1619289-targettransform) 属性为界面的某些部分创建反向旋转矩阵。