系统字体大小变更时如何获取UIButton的最新尺寸?
当系统字体大小变更时,UIContentSizeCategory.didChangeNotification会立即触发,但此时UIKit尚未完成控件的布局更新,直接读取button.frame.width得到的还是旧值。你可以通过以下两种方式获取更新后的宽度:
方法1:强制触发布局更新后读取frame
在通知处理器中调用控件的layoutIfNeeded()方法,强制UIKit立即完成布局计算,之后就能获取到最新的frame宽度。注意必须在主线程执行UI操作:
@objc func handleFontSizeChange(_ notification: Notification) { DispatchQueue.main.async { // 强制按钮完成布局更新 self.acceptButton.layoutIfNeeded() self.cancelButton.layoutIfNeeded() let acceptWidth = self.acceptButton.frame.width let cancelWidth = self.cancelButton.frame.width // 计算总宽度(包含按钮间距) let totalRequiredWidth = acceptWidth + cancelWidth + 20 // 20为按钮间的水平间距 let dialogWidth = self.dialogView.bounds.width // 根据空间切换布局 self.buttonStackView.axis = totalRequiredWidth > dialogWidth ? .vertical : .horizontal self.buttonStackView.layoutIfNeeded() } }
方法2:直接读取控件的固有内容大小
UIButton的intrinsicContentSize会在字体变更后立即更新,这个值包含了按钮标题、内边距等因素决定的固有宽度,无需等待布局完成即可获取:
@objc func handleFontSizeChange(_ notification: Notification) { DispatchQueue.main.async { let acceptIntrinsicWidth = self.acceptButton.intrinsicContentSize.width let cancelIntrinsicWidth = self.cancelButton.intrinsicContentSize.width let totalRequiredWidth = acceptIntrinsicWidth + cancelIntrinsicWidth + 20 let dialogWidth = self.dialogView.bounds.width self.buttonStackView.axis = totalRequiredWidth > dialogWidth ? .vertical : .horizontal self.buttonStackView.layoutIfNeeded() } }
注意事项
- 注册通知时要确保在主线程,并且在视图销毁时移除通知:
override func viewDidLoad() { super.viewDidLoad() NotificationCenter.default.addObserver(self, selector: #selector(handleFontSizeChange(_:)), name: UIContentSizeCategory.didChangeNotification, object: nil) } deinit { NotificationCenter.default.removeObserver(self) }
- 如果使用UIStackView管理按钮,确保stackView的约束设置正确,比如给stackView设置水平方向的约束,让它的宽度受限于对话框的宽度,这样切换axis后布局能自动适配。
内容的提问来源于stack exchange,提问作者Mapleman
相关产品推荐
相关产品推荐

