UIFontPicker嵌入Sheet无法下滑关闭及样式适配问题
问题1:Sheet下滑关闭时出现多余空白区域
原因
直接将UIFontPickerViewController作为SwiftUI Sheet的根视图时,其内部布局系统与SwiftUI Sheet的容器环境不兼容。触发Sheet下滑手势时,UIFontPickerViewController的视图未正确响应容器布局变化,导致出现空白区域。
解决方案
将UIFontPickerViewController嵌入UINavigationController中,利用导航控制器的布局系统适配Sheet环境。修改SUIFontPicker的makeUIViewController方法:
public func makeUIViewController(context: UIViewControllerRepresentableContext<SUIFontPicker>) -> UINavigationController { let configuration = UIFontPickerViewController.Configuration() configuration.includeFaces = true configuration.displayUsingSystemFont = false let fontPickerVC = UIFontPickerViewController(configuration: configuration) fontPickerVC.delegate = context.coordinator return UINavigationController(rootViewController: fontPickerVC) }
嵌入导航控制器后,布局会正确响应Sheet下滑手势,空白区域问题将被修复。
问题2:在Sheet中实现原生present的UIFontPicker效果
原因
原生present(_:animated:)弹出UIFontPickerViewController时,系统会自动为其添加带标题和Cancel按钮的导航栏,且搜索栏固定顶部。但SwiftUI Sheet直接展示该VC时,导航栏未被正确初始化显示,导致丢失这些原生元素。
解决方案
通过UINavigationController包装UIFontPickerViewController,手动配置标题和Cancel按钮:
- 修改
SUIFontPicker的makeUIViewController方法:
public func makeUIViewController(context: UIViewControllerRepresentableContext<SUIFontPicker>) -> UINavigationController { let configuration = UIFontPickerViewController.Configuration() configuration.includeFaces = true configuration.displayUsingSystemFont = false let fontPickerVC = UIFontPickerViewController(configuration: configuration) fontPickerVC.delegate = context.coordinator let navController = UINavigationController(rootViewController: fontPickerVC) navController.navigationBar.topItem?.title = "Choose Font" // 添加Cancel按钮并绑定回调 let cancelBtn = UIBarButtonItem(barButtonSystemItem: .cancel, target: context.coordinator, action: #selector(context.coordinator.dismissSheet)) navController.navigationBar.topItem?.leftBarButtonItem = cancelBtn return navController }
- 在
Coordinator类中添加dismissSheet方法:
@objc func dismissSheet() { parent.presentationMode.wrappedValue.dismiss() }
修改后,Sheet弹出的字体选择器会拥有原生样式的标题、Cancel按钮,且搜索栏固定在顶部。
问题3:额外问题解答
子问题1:让UIButton自适应内容尺寸
原因
手动设置frame会固定按钮大小,无法根据标题内容自动调整,需要依赖Auto Layout实现自适应。
解决方案
关闭按钮的自动约束转换,添加Auto Layout约束:
override func viewDidLoad() { super.viewDidLoad() fontPicker.delegate = self let button = UIButton(type: .system) button.titleLabel?.font = .systemFont(ofSize: 17) button.setTitle("Choose font", for: .normal) button.addTarget(self, action: #selector(showFontPicker(sender:)), for: .touchUpInside) view.addSubview(button) // 启用Auto Layout button.translatesAutoresizingMaskIntoConstraints = false // 添加居中约束(可根据需求调整) NSLayoutConstraint.activate([ button.centerXAnchor.constraint(equalTo: view.centerXAnchor), button.centerYAnchor.constraint(equalTo: view.centerYAnchor) ]) }
按钮会根据标题内容自动计算并适配尺寸。
子问题2:仅修改文本字号而不改变字体族
原因
使用.font(.caption)会覆盖继承的字体族,系统会默认使用caption样式的字体,需要基于选中字体单独调整字号。
解决方案
基于选中的UIFont创建仅修改字号的新字体:
Text(selectedFont.fontName) .font(Font(UIFont(descriptor: selectedFont.fontDescriptor, size: UIFont.preferredFont(forTextStyle: .caption1).pointSize)))
iOS 16+可使用更简洁的withSize方法:
Text(selectedFont.fontName) .font(Font(selectedFont).withSize(UIFont.preferredFont(forTextStyle: .caption1).pointSize))
这样文本会保留选中的字体族,仅应用caption样式的字号。
内容的提问来源于stack exchange,提问作者BPDev

