1

Based on the two answers of @Tomas in this question, I write the following code to render user input as HTML. The HTMLStringView method works fine, but the HTMLText doesn't update when fullText changes.

The result

I have two questions:

(1) Why does HTMLStringView method works normally (that is, always get sync with user input)?

(2) And why does HTMLText fails? How should I fix it?


Below are the code.

import SwiftUI

struct Test: View {
    @State private var placeholderString: String = "Insert here"
    @State private var fullText: String = ""
    
    var body: some View {
        VStack {
            ZStack(alignment: .top) {
                if fullText.isEmpty {
                    TextEditor(text: $placeholderString)
                        .padding(.top, 20)
                }
                TextEditor(text: $fullText)
                    .padding(.top, 20)
                    .autocapitalization(.none)
                    .opacity(fullText.isEmpty ? 0.5 : 1)
            }
            HTMLText(html: """
<html>
<head>
</head>
<body>
<p>
//Does not update
\(fullText)
</p>
</body>
</html>
""")
            HTMLStringView(htmlContent: """
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>MathJax example</title>
  <script>MathJax = {
        tex:{
                inlineMath: [['$', '$'], ['\\(', '\\)']],
                tags: 'ams'
            },
        svg:{
                fontCache: 'global'
            }
        };
  </script>
  <script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script>
  <script id="MathJax-script" async
          src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js">
  </script>
</head>
<body>
<p>
\(fullText.replacingOccurrences(of: "\n\n", with: "<br />"))
</p>
</body>
</html>
""")
        }
    }
}

struct Test_Previews: PreviewProvider {
    static var previews: some View {
        Test()
    }
}

Here are the HTMLText.swift and HTMLStringView.swift.

// convert html to attributed string and show in a UITextView
import SwiftUI

struct HTMLText: UIViewRepresentable {

   let html: String

   func makeUIView(context: UIViewRepresentableContext<Self>) -> UITextView {
        let view = UITextView()
        DispatchQueue.main.async {
            let data = Data(self.html.utf8)
            if let attributedString = try? NSAttributedString(data: data, options: [.documentType: NSAttributedString.DocumentType.html], documentAttributes: nil) {
//                view.attributedText = attributedString
                view.textStorage.append(attributedString)
            }
        }

        return view
    }

    func updateUIView(_ uiView: UITextView, context: Context) {}
}
// render html directly
import WebKit
import SwiftUI

struct HTMLStringView: UIViewRepresentable {
    let htmlContent: String

    func makeUIView(context: Context) -> WKWebView {
        return WKWebView()
    }

    func updateUIView(_ uiView: WKWebView, context: Context) {
        uiView.loadHTMLString(htmlContent, baseURL: nil)
    }
}
Jinwen
  • 173
  • 1
  • 9

1 Answers1

0

You have to update the text of the TextView in updateUIView like this

func updateUIView(_ uiView: UITextView, context: Context) {
    uiView.text = html
}
davidev
  • 7,694
  • 5
  • 21
  • 56