user2058839
user2058839

Reputation:

Color in HTML string not updated when changing dark mode

I'm using SwiftUI, with a custom view for displaying HTML text in a Text :

struct HTMLText: UIViewRepresentable {

    private let html: String
    private let label = UILabel()
    
    init(html: String, font: String? = nil, size: CGFloat? = nil) {
        self.html = html
    }

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

        return label
    }

    func updateUIView(_ uiView: UILabel, context: Context) {}
}

In my main view, I'm using it that way :

struct ConsonantListItem: View {
    let consonant: Consonant
    
    var color : String = "#\(UIColor(named: "DefaultText")?.getHexString() ?? "")"

    var body: some View {
        VStack {
            HTMLText(html: "<div style=\"text-align:center\"><span style=\"font-size:20px;font-family:'Helvetica Neue';color:\(self.color)\">\(consonant.consonantRtgs)</span></div>")
                .frame(height: 20)
            // ...
        }
    }
}

If I'm running my application, this is working pretty well, and the color is the right one, wether I'm in light or dark mode (DefaultText is a color from assets which is black in light mode, and white in dark mode). But when I'm switching mode in the settings, then the color of this component is not updated. I tried to put the color with @State before, but nothing changed.

All the other colors are updated, but the only solution for this component is to kill and restart the app to make it the right color.

Am I missing something?

Upvotes: 2

Views: 961

Answers (1)

lagivan
lagivan

Reputation: 2818

Consider managing the color not inside html but by means of Swift. Also you might have to add the same code in updateUIView to trigger the changes. See the modified code:

struct HTMLText: UIViewRepresentable {

    private let html: String
    
    init(html: String, font: String? = nil, size: CGFloat? = nil) {
        self.html = html
    }

   func makeUIView(context: UIViewRepresentableContext<Self>) -> UILabel {
        let label = UILabel()
        setLabelText(label: label)
        return label
    }

    func updateUIView(_ uiView: UILabel, context: Context) {
        setLabelText(label: uiView)
    }


    private func setLabelText(label: UILabel) {
        DispatchQueue.main.async {
            let data = Data(html.utf8)
            if let attributedString = try? NSAttributedString(
                data: data,
                options: [.documentType: NSAttributedString.DocumentType.html],
                documentAttributes:nil) {
                    label.attributedText = attributedString
                    label.backgroundColor = UIColor.systemBackground
                    label.textColor = UIColor.label
                }
        }
    }
}

Instead of UIColor.systemBackground and UIColor.label you can use custom colors for light/dark modes like this - colorScheme == .dark ? Color.black : Color.white. For that you will also need to declare colorScheme in your struct this way - @Environment(\.colorScheme) var colorScheme

Upvotes: 0

Related Questions