为何动态文本字号增大时UIButton的titleLabel宽度反而变小?
问题描述
我有一个带次要文本的小型UIButton,希望文本字号不随系统动态文本设置变化。已经在UIButton的Configuration里做了相关设置,但titleLabel的宽度会随着动态文本字号增大而缩小,导致固定字号的文本被截断。之前文本会强制换行,虽然设置titleLineBreakMode = .byClipping能避免换行,但这只是临时解决办法。请问这是什么原因?
我的按钮配置代码:
var config = UIButton.Configuration.plain() config.titleLineBreakMode = .byClipping // 避免换行,但只是权宜之计 config.titleTextAttributesTransformer = UIConfigurationTextAttributesTransformer { incoming in var attributes = incoming attributes.font = .systemFont(ofSize: 16) return attributes } button.configuration = config
不同动态字号下的表现:
- Large字号下:按钮文本完整显示,无截断
- Accessibility 3字号下:按钮文本末尾被截断,无法完整展示
原因分析
虽然你通过titleTextAttributesTransformer强制设置了固定字号的字体,但UIButton的Configuration布局逻辑仍会参考系统当前动态文本字号来计算标题区域的可用宽度。也就是说,当系统动态字号调大时,按钮会优先为适配大字号预留布局空间,反而压缩了实际固定字号文本的显示宽度,最终导致文本截断。
解决方案
方法1:禁用titleLabel的动态文本适配
直接关闭按钮标题标签的动态字号适配开关,同时强制按钮重新计算自身的固有尺寸:
var config = UIButton.Configuration.plain() config.titleTextAttributesTransformer = UIConfigurationTextAttributesTransformer { incoming in var attributes = incoming attributes.font = .systemFont(ofSize: 16) return attributes } button.configuration = config // 关键:禁止titleLabel跟随系统动态字号调整 button.titleLabel?.adjustsFontForContentSizeCategory = false // 强制按钮重新计算固有尺寸,确保布局正确 button.invalidateIntrinsicContentSize()
方法2:重写按钮的固有尺寸计算
自定义按钮类,基于实际的标题文本和固定字体来计算正确的固有尺寸,彻底摆脱系统动态字号的影响:
class FixedTextSizeButton: UIButton { override var intrinsicContentSize: CGSize { guard let titleText = titleLabel?.text, let fixedFont = titleLabel?.font else { return super.intrinsicContentSize } // 计算文本实际占用的尺寸 let textSize = titleText.size(withAttributes: [.font: fixedFont]) // 加上Configuration设置的内边距 let config = configuration ?? .plain() let contentInsets = config.contentInsets return CGSize( width: textSize.width + contentInsets.leading + contentInsets.trailing, height: textSize.height + contentInsets.top + contentInsets.bottom ) } }
使用这个自定义按钮替代系统UIButton,就能确保无论系统动态字号如何变化,按钮都会根据固定字体的文本尺寸来布局,不会出现截断问题。
内容的提问来源于stack exchange,提问作者teradyl
相关产品推荐
相关产品推荐

