htmlcssiosswiftnsattributedstring

How to make an overlay for an image inside HTML text in NSAttributedString using CSS


I'm trying to parse html text that contains a youtube video. To display this video I use a preview image.

Initial text:

<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>\n<p><iframe loading=\"lazy\" title=\"Forza Horizon 5 : RTX 4090 24GB ( 8K Maximum Settings RTX ON / DLSS ON )\" width=\"500\" height=\"281\" src=\"https://www.youtube.com/embed/NcHyE_N1QDI?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" allowfullscreen></iframe></p>\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>

And then it looks like these:

<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. </p>\n<p><a href=\'https://www.youtube.com/watch?v=NcHyE_N1QDI\'><img src=\"https://img.youtube.com/vi/NcHyE_N1QDI/maxresdefault.jpg\" alt=\"\" width=\"393.0\"/></a></p>\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>

Then I use NSMutableAttributedString and assign new value to the UITextView's attributedText property.

The question is how to overlay an image with a play button on top of the preview image so that the user understands that this is a video. I assume this can be done using CSS, but don't know how to properly embed it in the code.

My code:

private func formatStringWithYTVideo(text: String, with width: Float) -> String {
        let iframeTexts = matches(for: ".*iframe.*", in: text)
        var newText = text
        
        if !iframeTexts.isEmpty {
            
            for iframeText in iframeTexts {
                let iframeId = matches(for: "((?<=(v|V)/)|(?<=be/)|(?<=(\\?|\\&)v=)|(?<=embed/))([\\w-]++)", in: iframeText);
                
                if !iframeId.isEmpty {
                    let htmlString = """
                    <p><a href='https://www.youtube.com/watch?v=\(iframeId[0])'><img src="https://img.youtube.com/vi/\(iframeId[0])/maxresdefault.jpg" alt="" width="\(width)"/></a></p>
                    """
                    
                    newText = newText.replacingOccurrences(of: iframeText, with: htmlString)
                }
            }
        }
        
        return newText
    }

Solution

  • It looks like this can't be achieved via UITextView and CSS because UITextView doesn't support the required attributes. I see at least two solutions.

    1: Using WKWebView instead of UITextView.

    2: Using the enumerateAttributes(in:options:using:) method. Get a list of attributes, find the desired image among them and replace it. You can create an image with an overlay using UIImageView and then convert it to an UIImage using UIGraphicsImageRenderer.