You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 14:45:33