Apple’s Mail app for iOS seems to treat a single email address as a single character once entered. When you try to edit the text, the whole email is selected.
In an attempt to mimic the email entry behaviour of the Mail app, I came upon an issue when rendering instances of
NSTextAttachment inside a
To accomplish this, I attempted to take snapshots of the entered text, and render it as a text attachment inline with any additional text (I might write another post about the data source behaviour another time).
The technique worked very well, except I found my text baseline was being thrown around a bit.
This had me stumped for a while. The
UIImage that I had generated for the
NSTextAttachment was simply a
UILabel rendered offscreen, and then sized to fit. Given that all my font sizes and string attributes matched up, there should not be any reason for the baselines to not line up perfectly.
I set a background colour on the label to investigate:
Aha! It looks like by default, the
UITextView renders instances of
NSTextAttachment on the baseline, extending upwards. This means the larger the image, the further down my baseline of the following text will be pushed.
You can see the snapshotted
UILabel has space at the bottom for it’s descenders, so we don’t want it rendering on the baseline.
After spending far too much time delving into various TextKit classes, I came up with a fairly straightforward solution.
I started checking out the
NSLayoutManager class, as that seemed to control how glyphs and characters are positioned in a text container. However it turns out that the
NSTextAttachment class already has a method returning it’s bounds:
So, I made a simple subclass of
NSTextAttachment which exposes a property for adjusting the y-offset of the attachment bounds.
Using this subclass now, I can grab the descender value from the font I’m using in my attributed string.
And bingo! The descender height was exactly the offset I needed to get all my
NSTextAttachment instances to line up nicely with my existing text.