【问题标题】:layoutSubviews getting called repeatedly when the app enters background state应用程序进入后台状态时重复调用 layoutSubviews
【发布时间】: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 会被重复调用。该应用程序不再响应用户的输入并继续为字体分配字体大小。

为什么会这样?

【问题讨论】:

  • 感谢您提出这个问题!

标签: ios swift autolayout


【解决方案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(stackoverflow.com/questions/26166737/… 供参考)。
  • 你的意思是自定义字体不能很好地在Interface Builder 中支持大小类。大小类始终存在,您始终可以使用 self.traitCollection.horizontalSizeClass 或 self.traitCollection.verticalSizeClass 获取它们,并且您始终可以覆盖 traitCollectionDidChange() 以使用它们。无论如何,这就是 IB 支持为您所做的一切。我将添加一个示例。
  • 感谢库尔特的精彩回答!一个真正的问题,你解决了它。
猜你喜欢
  • 2013-02-16
  • 1970-01-01
  • 2012-09-12
  • 1970-01-01
  • 2011-05-18
  • 2014-12-07
  • 1970-01-01
  • 1970-01-01
  • 2020-07-17
相关资源
最近更新 更多