应用程序进入后台状态时重复调用 layoutSubviews
Posted
技术标签:
【中文标题】应用程序进入后台状态时重复调用 layoutSubviews【英文标题】:layoutSubviews getting called repeatedly when the app enters background state 【发布时间】:2016-05-27 15:37:56 【问题描述】:我希望标签的字体大小与屏幕大小成正比。我将UILabel
类子类化以完成此操作:
@IBDesignable class MyCustomLabel: UILabel
override func layoutSubviews()
super.layoutSubviews()
self.font = UIFont(name: "myFontName", size: (self.font?.pointSize)!)
self.adjustsFontSizeToFitWidth = true
标签(其宽度与附加到它们的超级视图约束成比例)在应用程序首次启动时正确调整大小,但当它进入后台状态时layoutSubviews
会被重复调用。该应用程序不再响应用户的输入并继续为字体分配字体大小。
为什么会这样?
【问题讨论】:
感谢您提出这个问题! 【参考方案1】:在您的测试项目中,如果我在 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)
【讨论】:
谢谢库尔特!有没有办法在您的解决方案中以编程方式设置自定义字体?您可能知道,自定义字体不适用于 Size Classes(***.com/questions/26166737/… 供参考)。 你的意思是自定义字体不能很好地在Interface Builder 中支持大小类。大小类始终存在,您始终可以使用self.traitCollection.horizontalSizeClass
或 self.traitCollection.verticalSizeClass
获取它们,并且您始终可以覆盖 traitCollectionDidChange()
以使用它们。无论如何,这就是 IB 支持为您所做的一切。我将添加一个示例。
感谢库尔特的精彩回答!一个真正的问题,你解决了它。以上是关于应用程序进入后台状态时重复调用 layoutSubviews的主要内容,如果未能解决你的问题,请参考以下文章
当应用程序进入后台时,URLSessions 给 URLResponse nil
Swift - 当应用程序进入后台状态时,从 AppDelegate 更新 RootViewController 中的值
“applicationWillTerminate”没有被迅速调用
进入后台状态ios swift时防止websocket连接断开