如何让UISegmentedControl适配动态类型(Dynamic Type)?
我之前也踩过这个分段控制器适配动态类型的坑!默认情况下系统分段控件是支持动态类型的,但往往是我们的一些自定义配置或者疏忽把这个特性给覆盖了,给你几个具体的排查和修复步骤:
检查字体设置是否正确使用动态样式
如果你手动给分段控制器设置了固定字体(比如UIFont.systemFont(ofSize: 14)),那它肯定不会跟着系统文本大小变化。正确的做法是使用系统的动态字体样式,比如:// 使用预设的文本样式,比如标题3或者正文 let dynamicFont = UIFont.preferredFont(forTextStyle: .title3) // 用UIFontMetrics确保字体在不同内容尺寸下正确缩放 let scaledFont = UIFontMetrics(forTextStyle: .title3).scaledFont(for: dynamicFont) segmentedControl.setTitleTextAttributes([.font: scaledFont], for: .normal)别忘了同时设置
.selected状态的文本属性,不然选中态的字体可能还是固定大小。确认开启了自动调整字体开关
分段控制器有个属性adjustsFontForContentSizeCategory,默认应该是true,但如果你的代码或者IB里不小心把它设成了false,就会失去动态适配能力。可以在代码里显式设置:segmentedControl.adjustsFontForContentSizeCategory = true或者在Storyboard/XIB里,选中分段控制器,在Attributes Inspector里找到“Adjust Font For Content Size Category”选项并勾选。
检查自动布局约束是否限制了控件大小
如果分段控制器的宽度被设为固定值,或者约束太死板,就算字体放大了,控件也没办法展开显示完整的大字体。建议给分段控制器设置leading、trailing约束(或者和父视图的边距约束),不要固定宽度,让它能根据内容自动调整尺寸。如果需要限制最大宽度,可以设置maxWidth约束。监听内容尺寸变化通知(针对自定义场景)
如果你对分段控制器做了比较复杂的自定义(比如自定义了内部视图),可能需要手动监听系统文本大小变化的通知,然后重新更新字体和布局:override func viewDidLoad() { super.viewDidLoad() NotificationCenter.default.addObserver(self, selector: #selector(updateSegmentedControlFont), name: UIContentSizeCategory.didChangeNotification, object: nil) } @objc private func updateSegmentedControlFont() { let dynamicFont = UIFont.preferredFont(forTextStyle: .title3) let scaledFont = UIFontMetrics(forTextStyle: .title3).scaledFont(for: dynamicFont) segmentedControl.setTitleTextAttributes([.font: scaledFont], for: .normal) segmentedControl.setTitleTextAttributes([.font: scaledFont], for: .selected) // 如果需要的话,强制刷新布局 segmentedControl.layoutIfNeeded() }记得在视图销毁时移除通知观察者,避免内存泄漏。
排查iOS版本和分段控制器样式的影响
比如在iOS 13及以后,分段控制器的style属性(比如.prominent、.plain)对动态类型的支持更完善,如果你的分段控制器用了比较旧的样式,可能需要调整样式或者额外处理。另外,iOS 14+新增的一些特性也可能影响,确保你的适配逻辑是针对目标版本做的。
按照上面的步骤排查下来,基本就能解决分段控制器不跟随动态类型的问题了,我之前就是因为手动设置了固定字体,导致控件死活不缩放,改完动态字体就正常了!
内容的提问来源于stack exchange,提问作者MarkAurelius

