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

SwiftUI中RichEditorView发送/编辑时内容无法更新的问题求助

解决方案:修复RichEditorView的内容同步问题

问题根源

你的RichTextEditor实现中,updateUIView方法是空的。SwiftUI在绑定的htmlText值发生变化时会调用这个方法,但你没有将新的内容同步到RichEditorView实例,导致编辑器显示的内容无法跟随绑定值更新(比如发送后清空、编辑回填场景)。同时,直接同步可能触发双向绑定的循环更新,需要添加内容一致性判断。

核心修复步骤

  1. 实现updateUIView方法:同步绑定的htmlText到编辑器,同时避免循环更新
  2. 优化内容变化回调:确保编辑器内容变化时仅在必要时更新绑定值

修改后的完整代码

struct RichTextEditor: UIViewRepresentable {
    
    class Coordinator: RichEditorDelegate, RichEditorToolbarDelegate {
        
        var parent: RichTextEditor
        var isDefaultFocus: Bool
        @Binding var colorPickerType: ColorPickerType?
        
        init(_ parent: RichTextEditor, isDefaultFocus: Bool = false, colorPickerType: Binding<ColorPickerType?>) {
            self.parent = parent
            self.isDefaultFocus = isDefaultFocus
            self._colorPickerType = colorPickerType
            NotificationCenter.default.addObserver(self, selector: #selector(colorPicked(notification:)), name: AppNotifications.colorPicked, object: nil)
        }
        
        func richEditorTookFocus(_ editor: RichEditorView) {
            
        }
        
        func richEditorLostFocus(_ editor: RichEditorView) {
            
        }
        
        // 优化:仅当内容不同时更新绑定值,避免循环
        func richEditor(_ editor: RichEditorView, contentDidChange content: String) {
            if content != parent.htmlText {
                parent.htmlText = content
            }
        }
        
        func richEditorToolbarChangeTextColor(_ toolbar: RichEditorToolbar) {
            colorPickerType = .text
        }
        
        func richEditorToolbarChangeBackgroundColor(_ toolbar: RichEditorToolbar) {
            colorPickerType = .background
        }
        
        func richEditorToolbarInsertLink(_ toolbar: RichEditorToolbar) {
            if let hasSelection = toolbar.editor?.hasRangeSelection, hasSelection, let href = toolbar.editor?.runJS("document.getSelection().getRangeAt(0).toString()"){
                toolbar.editor?.insertLink(href, title: "Link")
            }
        }
        
        func richEditorDidLoad(_ editor: RichEditorView) {
            editor.setEditorBackgroundColor(UIColor(parent.editorBackgroundColor))
            editor.setEditorFontColor(UIColor(Color.primary))
            if isDefaultFocus {
                editor.focus()
            }
        }
        
        func richEditor(_ editor: RichEditorView, heightDidChange height: Int) {
            withAnimation {
                if CGFloat(height) > parent.maxHeight {
                    parent.height = parent.maxHeight
                } else if CGFloat(height) < parent.minHeight {
                    parent.height = parent.minHeight
                } else if CGFloat(height) != parent.height {
                    parent.height = CGFloat(height)
                }
            }
        }
        
        @objc func colorPicked(notification: NSNotification) {
            if let colorPickerType = notification.userInfo?["colorPickerType"] as? ColorPickerType, let selectedColor = notification.userInfo?["color"] as? UIColor {
                switch colorPickerType {
                case .text :
                    self.parent.toolbar.editor?.setTextColor(selectedColor)
                case .background :
                    self.parent.toolbar.editor?.setTextBackgroundColor(selectedColor)
                }
            }
        }
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator(self, isDefaultFocus: isDefaultFocus, colorPickerType: $colorPickerType)
    }
    
    @Binding var htmlText: String
    @Binding var colorPickerType: ColorPickerType?
    var isDefaultFocus : Bool
    var minHeight: CGFloat
    @Binding var height: CGFloat
    var maxHeight: CGFloat
    let toolbar: RichEditorToolbar = RichEditorToolbar(frame: CGRect(x: 0, y: 0, width: 100, height: 44))
    var editorBackgroundColor = Color.red
    
    func makeUIView(context: Context) -> RichEditorView {
        let editor = RichEditorView(frame: .zero)
        editor.delegate = context.coordinator
        editor.html = htmlText
        editor.isScrollEnabled = true
        editor.placeholder = "Write something..."
        
        toolbar.options = [
            RichEditorDefaultOption.bold,
            RichEditorDefaultOption.italic,
            RichEditorDefaultOption.strike,
            RichEditorDefaultOption.underline,
            RichEditorDefaultOption.textColor,
            RichEditorDefaultOption.textBackgroundColor,
            RichEditorDefaultOption.link,
            RichEditorDefaultOption.orderedList,
            RichEditorDefaultOption.unorderedList,
            RichEditorDefaultOption.indent,
            RichEditorDefaultOption.outdent,
            RichEditorDefaultOption.alignLeft,
            RichEditorDefaultOption.alignCenter,
            RichEditorDefaultOption.alignRight,
        ]
        
        toolbar.editor = editor
        toolbar.delegate = context.coordinator
        
        editor.inputAccessoryView = toolbar
        
        return editor
    }
    
    // 新增:同步绑定值到编辑器,避免循环更新
    func updateUIView(_ uiView: RichEditorView, context: Context) {
        if uiView.html != htmlText {
            uiView.html = htmlText
        }
    }

}

额外优化建议

  • 编辑消息时,如果需要自动聚焦编辑器,可以在updateUIView中添加逻辑:当htmlText非空且是编辑场景时,调用uiView.focus()
  • 若编辑器初始化时内容未正确加载,可以在richEditorDidLoad中再次设置editor.html = parent.htmlText

内容的提问来源于stack exchange,提问作者Vikash Kumar Chaubey

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 13:07:45