SwiftUI TextEditor调整字体大小后出现卡顿闪烁等异常原因
SwiftUI TextEditor动态调字体后UI异常的解决办法
你遇到的滚动跳变、光标错位、文本闪烁问题,本质是SwiftUI原生TextEditor在字体大小变化时,底层UITextView的状态(光标位置、滚动偏移)没有被正确保留,导致重绘时出现异常。
以下是可行的解决方案:
方案一:封装UITextView自定义实现(推荐)
直接基于UIKit的UITextView封装,手动控制字体更新时的状态保留,彻底避免原生组件的bug:
struct CustomTextEditor: UIViewRepresentable { @Binding var text: String @Binding var fontSize: CGFloat func makeUIView(context: Context) -> UITextView { let textView = UITextView() textView.font = .systemFont(ofSize: fontSize, weight: .semibold) textView.delegate = context.coordinator return textView } func updateUIView(_ uiView: UITextView, context: Context) { // 仅在文本实际变化时更新,避免字体调整时干扰内容 if uiView.text != text { uiView.text = text } // 保存当前状态:光标位置、滚动偏移 let selectedRange = uiView.selectedRange let contentOffset = uiView.contentOffset // 更新字体 uiView.font = .systemFont(ofSize: fontSize, weight: .semibold) // 恢复状态,避免错乱 uiView.selectedRange = selectedRange uiView.setContentOffset(contentOffset, animated: false) } func makeCoordinator() -> Coordinator { Coordinator(self) } class Coordinator: NSObject, UITextViewDelegate { var parent: CustomTextEditor init(_ parent: CustomTextEditor) { self.parent = parent } func textViewDidChange(_ textView: UITextView) { parent.text = textView.text } } } // 使用示例 struct ContentView: View { @State var text: String = "" @State var textSize: CGFloat = 20.0 var body: some View { VStack { Slider(value: $textSize, in: 20.0...80.0) CustomTextEditor(text: $text, fontSize: $textSize) .padding() .border(.gray) } .padding() } }
方案二:原生TextEditor的临时修复(不推荐)
如果不想自定义组件,可尝试通过onChange监听字体变化,结合PreferenceKey获取底层UITextView的状态,但实现复杂且稳定性不如方案一,核心思路是:
- 用PreferenceKey获取TextEditor对应的UITextView实例
- 在
onChange(of: textSize)时保存光标位置和滚动偏移 - 更新字体后手动恢复这些状态
补充说明
你的主线程假设不成立,这个问题是SwiftUI原生TextEditor的封装缺陷,在iOS 16.x的部分版本中存在,升级到iOS 17+后该问题可能被修复,但如果需要兼容旧系统,方案一是最可靠的选择。
内容的提问来源于stack exchange,提问作者Jeff
相关产品推荐
相关产品推荐

