Detecting Truncation in UITextViews
Do your text views show…?
One of the challenges you might encounter when working with
UITextViews is that they don’t provide a straightforward way to detect whether or not they are displaying truncated text.
UILabel you can check for truncation by calculating the size of the text within the label and comparing that with the bounds of the label itself. If the text extends beyond the bounds then it’s being displayed as truncated.
The challenge with
UITextView is that, by design, it can hold text that is far larger than its bounds.
This is the essence of how a scrolling text view operates. That feature breaks our ability to quickly check for truncation, so to begin with, we need to work with a textview that has scrolling disabled.
This is where some knowledge on TextKit and how iOS lays out and manipulates rendered text comes in handy. I highly recommend reading up on the TextKit official documentation, along with this excellent write-up by the folks over at objc.io.
From here on, I will assume you have at least a cursory understanding of text layout within iOS.
Since we can’t rely only on the bounds of the
UITextView for making this check, we have to lean on the
NSLayoutManager within the textview itself.
So, if we have a textview that is displaying truncated text like below then we can use the following snippet to detect that.
What are we doing here exactly? Well,
NSLayoutManager works with line fragments for laying out text. These are essentially rectangles that define the bounds for each line of text.
Again, the objc.io article goes into far more depth than I can here, but the gist is that using that concept of line fragments, we can ask the layout manager to search through them to find the truncation glyph we care about (…).
If it’s found, we can stop the traversal and know that our text is being rendered in a truncated fashion.
Side-note: Why can’t we just search the
textContainer.text property for the
Well, under the hood, the
textContainer has no concept of the truncation glyph existing at all. That work is done a layer above by the
NSLayoutManager before the text is finally rendered to the screen.
This solution on its own will work great for detecting tail truncation. But what if the textview just isn’t wide enough or tall enough to render all of the text?
For that, we will need to inspect the text container’s characters and glyphs to compare them. An example of such a textview is displayed below, along with the following snippet detailing how the detection works.
This should now cover both cases where the
lineBreakMode is set to
byTruncatingTail along with
byWordWrapping. You can find the full gist of this solution here.
As you can see, it’s not very straightforward to detect whether or not some text is displayed in a truncated fashion. This is likely by design from Apple since it would open up a ton of edge cases, and goes somewhat against the purpose of
Even with the solution above, it’s only possible to detect truncation reliably when using the three
lineBreakMode settings listed above. It also requires that the textview being inspected has scrolling disabled.
So, use at your own discretion. In my case, the need for this behavior arose from a product requirement where we were displaying shortened comments and we wanted to allow for inline expansion behavior.
Also, I would like to give a huge shoutout to Dave DeLong as he sat with me for a long time to help figure out this solution, and most of the credit for it working properly goes to him.
Anyway, I hope this has helped you out or at least been an informative read. Please leave a comment below if you find an error in my solution or if you have a different approach to this that worked for you. Cheers!