我希望标签的字体大小与屏幕大小成正比。我已经将UILabel
类子类化为完成此任务:
@IBDesignable class MyCustomLabel: UILabel {
override func layoutSubviews() {
super.layoutSubviews()
self.font = UIFont(name: "myFontName", size: (self.font?.pointSize)!)
self.adjustsFontSizeToFitWidth = true
}
}
首次启动应用时,标签(与超级视图约束成比例的宽度)会正确调整大小,但是当它进入背景时,会重复调用layoutSubviews
状态。该应用不再响应用户'输入并保持为字体指定字体大小。
Download test project.为什么会这样?
答案 0 :(得分:4)
在你的测试项目中,如果我在iPhone上运行,我没有看到在后台调用layoutSubviews()
。它只发生在iPad上。
那是因为您的应用支持多任务处理:
layoutSubviews()
被调用。那是完全正常的。真正的问题是你正在创建一个“布局循环”。您在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)
}