ios - 当来自 NotificationCenter 时,为什么调整标签大小需要延迟才能按预期更新?

标签 ios swift multithreading uikit uilabel

我正在向我的应用程序添加动态类型,当通过以下代码触发 UIContentSizeCategoryDidChangeNotification 通知时,我正在尝试更新以编程方式创建的 UILabel 的框架:

private func configureNotificationCenter() {
    NotificationCenter.default.addObserver(self, selector: #selector(contentSizeCategoryDidChange) , name: NSNotification.Name("UIContentSizeCategoryDidChangeNotification"), object: nil)
}

@objc private func contentSizeCategoryDidChange() {
    self.delegate?.didChangeContentSize()
}

然后在要更新 UILabel 的 View 中,我更新框架:

func didChangeContentSize() {
    DispatchQueue.main.asyncAfter(deadline: .now() + 0.1, execute: {
        self.label.sizeToFit()
    })
}

由于某些原因,如果不调用 DispatchQueue.main.asyncAfter ...,框架将无法正确设置。起初,我尝试在没有 0.1 秒延迟的情况下调用 DispatchQueue.main,因为我知道 UI 更新应该始终在主线程上进行,但这似乎没有任何区别。

虽然延迟 0.1 秒不是什么大问题,而且我认为任何用户都不会注意到,但了解正在发生的事情以及为什么需要延迟会很棒。

编辑:这是我创建标签的方式

label = UILabel(frame: CGRect(x: 0, y: 100, width: view.frame.width, height: 200))
label.backgroundColor = .red
label.numberOfLines = 0
label.lineBreakMode = .byWordWrapping
label.text = "Test title that should resize"
label.adjustsFontForContentSizeCategory = true
label.textAlignment = .center

let userFont =  UIFontDescriptor.preferredFontDescriptor(withTextStyle: .title1)
let pointSize = userFont.pointSize
let customFont = UIFont(name: "AvenirNext-DemiBold", size: pointSize)
label.font = UIFontMetrics.default.scaledFont(for: customFont!)

label.sizeToFit()
view.addSubview(label)

最佳答案

这听起来很像自动布局问题。当您不延迟时,Auto Layout 正在调整标签的固有大小并在您修改标签的框架后运行,因此您的 sizeToFit 来得太早并使用以前的固有大小。

当您延迟 0.1 秒时,Auto Layout 首先运行并设置标签的固有尺寸,然后您的 sizeToFit() 调用使用新的固有尺寸来设置框架。


使用自动布局

使用自动布局让事情变得更轻松。不要搞乱 frame 大小、sizeToFit 和通知,只需为标签的前导、尾随和上边缘设置约束和自动布局 将在字体大小更改时自动调整标签大小:

label = UILabel()
label.backgroundColor = .red
label.numberOfLines = 0
label.lineBreakMode = .byWordWrapping
label.text = "Test title that should resize"
label.adjustsFontForContentSizeCategory = true
label.textAlignment = .center

let userFont =  UIFontDescriptor.preferredFontDescriptor(withTextStyle: .title1)
let pointSize = userFont.pointSize
let customFont = UIFont(name: "AvenirNext-DemiBold", size: pointSize)
label.font = UIFontMetrics.default.scaledFont(for: customFont!)

view.addSubview(label)

label.translatesAutoresizingMaskIntoConstraints = false
label.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
label.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
label.topAnchor.constraint(equalTo: view.topAnchor).isActive = true

关于ios - 当来自 NotificationCenter 时,为什么调整标签大小需要延迟才能按预期更新?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49183838/

相关文章:

ios - 如何在swift中比较两个字符串?

ios - 无法使用 iOS 应用程序中的 Url 方案从 Web URL 打开 Microsoft PowerPoint iPad 应用程序中的 powerpoint 演示文稿

ios - 调整图像大小会降低分辨率

java - Android camera : Threads? 哪个应该做什么

multithreading - Prange 减慢 Cython 循环速度

ios - 了解崩溃日志

ios - 核心数据建议

ios - 调用 UIGraphicsBeginImageContext 时出现无效上下文 0x0 错误。调用任何 Core Graphics 'AddPath' 函数时也会出现类似的错误

swift - 第一次加载应用程序时意外发现 nil

java - 从java中的另一个线程访问一个线程的变量