This is a continuation of Getting CGRect for text in a UITextView for the purpose of highlighting with a CALayer. I'm having trouble with getting the correct rectangle for the ranges in each line fragment.
NSString* searchString = @"Returns the range of characters that generated";
NSRange match = [[[self textView]text]rangeOfString:searchString];
NSRange matchingGlyphRange = [manager glyphRangeForCharacterRange:match actualCharacterRange:NULL];
[manager enumerateLineFragmentsForGlyphRange:matchingGlyphRange usingBlock:
^(CGRect lineRect, CGRect usedRect, NSTextContainer *textContainer, NSRange lineRange, BOOL *stop) {
NSRange currentRange = NSIntersectionRange(lineRange, matchingGlyphRange);
[manager enumerateEnclosingRectsForGlyphRange:currentRange withinSelectedGlyphRange:NSMakeRange(NSNotFound, 0) inTextContainer:textContainer usingBlock:
^(CGRect rect, BOOL* stop) {
if (usedRect.origin.y == rect.origin.y && NSLocationInRange(currentRange.location, lineRange)) {
CGRect theRect = [manager boundingRectForGlyphRange:currentRange inTextContainer:textContainer];
CALayer* roundRect = [CALayer layer];
[roundRect setFrame:theRect];
[roundRect setBounds:theRect];
[roundRect setCornerRadius:5.0f];
[roundRect setBackgroundColor:[[UIColor blueColor]CGColor]];
[roundRect setOpacity:0.2f];
[roundRect setBorderColor:[[UIColor blackColor]CGColor]];
[roundRect setBorderWidth:3.0f];
[roundRect setShadowColor:[[UIColor blackColor]CGColor]];
[roundRect setShadowOffset:CGSizeMake(20.0f, 20.0f)];
[roundRect setShadowOpacity:1.0f];
[roundRect setShadowRadius:10.0f];
[[[self textView]layer]addSublayer:roundRect];
*stop = YES;
}
}];
}];
This my current attempt. I'm basically using enumerateLineFragmentsForGlyphRange:usingBlock: to cycle through each line. Then i'm using enumerateEnclosingRectsForGlyphRange:withinSelectedGlyphRange:usingBlock: to make sure the range of the text on the current line matches up with the line's range and has the same Y coordinate. Sometimes this works, and sometimes it doesn't.
It seems that if the search text is near a return it draws the highlight way off. (the y coordinate).
In this screenshot "Returns the range of characters that generated" is supposed to be highlighted.
It seems if the text is not near a return or whitespace this works correctly:
Am I missing something?
UPDATE:
I've narrowed the problem down a bit, I believe enumerateLineFragmentsForGlyphRange: usingBlock: is skipping over lines which have returns.
I've found the solution:
Instead of using enumerateEnclosingRectsForGlyphRange: I use the NSString method enumerateSubstringsInRange:options:usingBlock:
I enumerate the line fragments as usual, but instead of trying to use the enclosing rect enumeration method, I enumerate each character on the line while building the rect for the layer.
}
I'm still working on multiple matches, i'll update the code once I get that working.