iosios7uilabeltextkit

How do I locate the CGRect for a substring of text in a UILabel?


For a given NSRange, I'd like to find a CGRect in a UILabel that corresponds to the glyphs of that NSRange. For example, I'd like to find the CGRect that contains the word "dog" in the sentence "The quick brown fox jumps over the lazy dog."

Visual description of problem

The trick is, the UILabel has multiple lines, and the text is really attributedText, so it's a bit tough to find the exact position of the string.

The method that I'd like to write on my UILabel subclass would look something like this:

 - (CGRect)rectForSubstringWithRange:(NSRange)range;

Details, for those who are interested:

My goal with this is to be able to create a new UILabel with the exact appearance and position of the UILabel, that I can then animate. I've got the rest figured out, but it's this step in particular that's holding me back at the moment.

What I've done to try and solve the issue so far:

I'd bet that the right answer to this involves one of the following:


Update: Here's a github gist with the three things I've tried so far to solve this issue: https://gist.github.com/bryanjclark/7036101


Solution

  • Following Joshua's answer in code, I came up with the following which seems to work well:

    - (CGRect)boundingRectForCharacterRange:(NSRange)range
    {
        NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:[self attributedText]];
        NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
        [textStorage addLayoutManager:layoutManager];
        NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:[self bounds].size];
        textContainer.lineFragmentPadding = 0;
        [layoutManager addTextContainer:textContainer];
    
        NSRange glyphRange;
    
        // Convert the range for glyphs.
        [layoutManager characterRangeForGlyphRange:range actualGlyphRange:&glyphRange];
    
        return [layoutManager boundingRectForGlyphRange:glyphRange inTextContainer:textContainer];
    }