在您的测试项目中,如果我在 iPhone 上运行,我看不到 layoutSubviews() 在后台被调用。它只发生在 iPad 上。
那是因为您的应用支持多任务处理:
- 当您的应用停用时,iOS 会将其调整为不同的大小,以便为应用切换器拍摄其快照。这些调整大小会导致您的视图的
layoutSubviews() 被调用。这是完全正常的。
- iOS 然后将您的应用恢复为原始大小。
真正的问题是您正在创建一个“布局循环”。您在layoutSubviews() 中的代码导致您自己的视图布局无效,因此系统需要再次运行布局过程。然后布局运行,你再做一次,它会再次发生。
具体原因是:
self.font = UIFont(name: fontName, size: fontSize)
更改标签的字体会导致其 intrinsicSize 发生更改,这意味着其超级视图可能需要更新其布局,因此需要再次运行布局过程。在layoutSubviews() 中这样做是个坏主意,因为它会导致布局循环。您实际上应该只更改子视图的属性,而不是视图本身。
您认为为什么需要在layoutSubviews() 中执行此操作?在布局过程之外,可能有一个更好的放置位置。在您的示例中,我根本看不出这段代码有什么用处。
设置adjustsFrameSizeToWidth 一次会更有意义,然后不要在layoutSubviews() 中做任何事情:
override init(frame: CGRect) {
super.init(frame: frame)
self.adjustsFontSizeToFitWidth = true
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.adjustsFontSizeToFitWidth = true
}
如果您尝试根据大小类更改字体大小,可以在代码中通过覆盖 traitCollectionDidChange() 来实现:
override func traitCollectionDidChange(previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
var fontSize: CGFloat
if (self.traitCollection.horizontalSizeClass == .Regular) {
fontSize = 70
}
else {
fontSize = 30
}
self.font = UIFont(name: fontName, size:fontSize)
}