如果您依赖于大小更改来构建自适应布局,则应该检查iOS 13的代码.UIKit现在可以预测视图的初始特征,因此您不能假设traitCollectionDidChange
在视图首次添加到视图层次结构时将调用它。
特征集合和大小类
Apple在iOS 8中首次引入了特征集合来描述用户界面的环境属性(特征)。水平和垂直尺寸类特征粗略地指示宽度或高度是否受约束(紧凑)或不受约束(常规)。
我们的想法是构建布局变体以适应紧凑和常规尺寸类。您可以直接在Interface Builder中添加特征变体,或者如果您愿意,可以使用以下方法:
-
traitCollectionDidChange
(查看控制器或视图) -
willTransition(to:with:)
(查看控制器)
其中我对紧凑和常规尺寸宽度有不同的约束集。我根据水平尺寸类在约束之间切换:
private func enableConstraintsForWidth(_ horizontalSizeClass: UIUserInterfaceSizeClass) {
if horizontalSizeClass == .regular {
NSLayoutConstraint.deactivate(compactConstraints)
NSLayoutConstraint.activate(regularConstraints)
} else {
NSLayoutConstraint.deactivate(regularConstraints)
NSLayoutConstraint.activate(compactConstraints)
}
}
切换发生在traitCollectionDidChange
:
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
if traitCollection.horizontalSizeClass != previousTraitCollection?.horizontalSizeClass {
enableConstraintsForWidth(traitCollection.horizontalSizeClass)
}
}
在iOS 12及更早版本中,UIKit traitCollectionDidChange
在将视图添加到视图层次结构时调用该方法。这previousTraitCollection
是nil
第一次。当前值traitCollection
在视图控制器的属性中可用。我依赖于在首次添加视图时调用此方法以启用正确的初始约束集。
iOS 13中的变化
在iOS 13中,在您将视图添加到视图层次结构之前,UIKit会在创建视图时设置视图的特征。UIKit根据上下文猜测视图的可能特征。然后,当您将视图添加到视图层次结构时,实际特征将从父级继承。
如果UIKit正确猜测,则在将视图添加到视图层次结构时,视图的特征集合不会更改。traitCollectionDidChange
如果您依赖它来设置布局的初始状态,则不再接收调用问题。
一种可能的解决方法是从viewDidLoad
:
override func viewDidLoad() {
super.viewDidLoad()
...
enableConstraintsForWidth(traitCollection.horizontalSizeClass)
}
在iOS 12及更早版本中,Apple没有承诺UIKit此时正确设置了视图的特征。但是,我们应该调用traitCollectionDidChange
何时将视图添加到层次结构中,以便我们可以更正。
在iOS 13中,这基于预测的特征设置布局的初始状态。如果UIKit猜错了,我们会调用traitCollectionDidChange
最终的size类。无论哪种方式,我们最终都得到了正确配置的布局。
布局子视图
Apple建议的另一种方法是在其中一种布局方法中执行涉及特征的任何工作:
UIViewController.viewWillLayoutSubviews()
UIView.layoutSubviews()
UIViewController.viewDidLayoutSubviews()
特征集合在布局发生之前更新,因此在上述任何方法中都是最新的。这种方法唯一需要注意的是,在视图控制器或视图的生命周期中可以多次调用布局方法,因此您应该采取措施避免重复工作:
private var firstTime = true
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
if firstTime {
firstTime = false
enableConstraintsForWidth(traitCollection.horizontalSizeClass)
}
}
我们在第一次执行布局时设置布局状态,然后依赖于traitCollectionDidChange
任何未来的大小类更改。
我该怎么办?
检查您的代码是否有任何用途traitCollectionDidChange
。如果您依赖于调用它来设置视图的初始布局,请从布局子视图方法之一或类似的地方调用您的设置代码viewDidLoad
。
如果您只在Interface Builder中使用特征变体,则无需执行任何操作。
调试特征集合更改
最后一个提示。通过向方案添加启动参数,您可以在每次更改时记录先前和当前特征集合:
-UITraitCollectionChangeLoggingEnabled YES
不要忘记领先的“ - ”:

每次traitCollectionDidChange
调用它都会记录更改,前一个和当前的特征集合:
[TraitCollectionChange] Sending -traitCollectionDidChange: to ...
► trait changes: { HorizontalSizeClass: Unspecified → Regular;
VerticalSizeClass: Unspecified → Regular }
► previous: <UITraitCollection: 0x600003f2c6c0; DisplayScale = 1, ...
► current: <UITraitCollection: 0x600003f14540; DisplayScale = 1, ...
阅读更多
Apple描述了在暗模式下WWDC会话的最后部分的变化:
扫码进交流群 有技术的来闲聊 没技术的来学习

网友评论