Display image-containing HTML using UILabel and detect if an image is tapped in your iOS apps
Make your UILabel graphic and tappable
The UILabel view is probably the most widely used UI element in iOS app development. Almost all iOS apps need to use it to display some text content somewhere. Most of the time, plain text is sufficient to serve our purposes where we just need to set the text property of the label like below.
let label = UILabel()
label.text = "Some Plain Text"
In some other use cases, we need to display richer information like some HTML including texts and images in our apps. Certainly, some developers may choose a web view or text view to display the HTML content. However, given the familiarity of UILabel to most iOS developers, I’m showing you how to achieve this goal using UILabel step by step.
Part I. Display HTML with an Image
Step 1. The Set-up
For demonstration purposes, we’ll just simply create a Single View Playground in your Xcode (File -> New -> Playground, select the Single View option). Give it a name you want and save it somewhere you prefer.
Incidentally, Xcode somehow knew that we would be going to use a UILabel in our app, so it created the “Hello World!” label displayed on the view if we run the playground by clicking the play button.
Step 2. Configure the UILabel
Next, we’re going to configure the label in a way that will allow us to display the HTML content properly. We’re going to remove the default text and configuration by commenting out the first three lines as shown below.
Lines 4 and 5 are necessary to allow the label to display multiple lines and break the lines by wrapping at the word boundaries. The Lines 6–9 are just to use auto-layout to align the label to the top of the view. As long as you set the constraints for the leading, top, and training, you don’t need to set the bottom constraint, as the height of a label without a line number constraint will be automatically adjusted to fit its content.
Step 3. Display the HTML Content
To display an HTML content, we’ll just create a string using a simple HTML markup example as shown below.
let htmlString = "<html><body><h1>This is the title</h1><p>This is the first paragraph.</p><img src=\"https://miro.medium.com/max/9216/1*QzxcfBpKn5oNM09-vxG_Tw.jpeg\" width=\"360\" height=\"240\"><p>This is the second paragraph.</p><p>This is the third paragraph.</p><p>This is the fourth paragraph.</p><p>This is the last paragraph.</p></body></html>"
If we simply set the label’s text property to this string, the label will just display exactly the same string, which is not what we wanted! So what’s the trick then?
Well, the trick involves two steps. First, convert the HTML string to an attributed string using the extension function above. Basically, this function first converts the string to the data format, which will then be converted to an attributed string by specifying the document type as the HTML.
Second, set the label’s attributedText as the converted attributed string. Also, remember to comment out the line that sets the text property. One thing to note is that the image is rendered as an NSTextAttachment, which will be needed to determine if the image is tapped in Part II.
label.attributedText = htmlString.convertToAttributedFromHTML()
When we run the playground again, we’ll see that the label will display the HTML content properly as shown below.
Part II. Image Tap Gesture Detection
Now, we are able to use an UILabel to display the HTML content that contains an image. How do we know if the image is tapped? It’s a common use case, because sometimes we may allow the user to enlarge the image or save the image if they want.
Step 1. Make the label responsive to taps
As shown in the code snippet (Lines 10 and 11) in Step 2 of the first part, we need to enable the user interaction property for the label and add a tap gesture recognizer to the label, such that when the label is tapped, the corresponding function can be called to handle the tap event.
Step 2. Calculate the tapped character index
When the label is tapped, in order to find out whether the image is tapped, we first need to calculate the tap location in terms of the character index within the label’s attributed string. We can use the following extension function available to an UILabel.
Specifically, this function has two steps. First, it will create instances for NSLayoutManager, NSTextContainer, and NSTextStorage. These instances collectively manage the layout and rendering the attributed string for this label by creating a rectangular region. Second, based on the location of the tap gesture, the function will calculate the location of the tap within the text container, and this location will be used to find out the character index from the layout manager.
Step 3. Determine if an image is tapped
Once we have the character index that is tapped, we’ll inspect if there is an NSTextAttachment, because as mentioned before, the image is rendered as a text attachment of the attributed string in the label. The following code shows you how it’s implemented.
For the purposes of this tutorial, we’ll just simply present an alert controller to tell us if the tap falls on the image. As you can see in the following animated image, our function successfully determines if the tap is on the image or not. Hooray!
By now, we have learned how to use an UILabel to display HTML content that has images. With that, your labels can be graphic instead of just showing plain texts.
We have also learned how to detect if the image is tapped. We would love to know that because our app users may want to save the image or view an enlarged version of the image occupying the entire screen.