Getting CGRect for text in a UITextView for the purpose of highlighting with a CALayer

3.8k views Asked by At

I am trying to draw a transparent CALayer in a UITextView in order to highlight matched text in a search.

I've figured out the correct way to do this, but still haven't found the correct coordinates. I need to find the origin of the text container. Right now, I get the textView's origin, and offset the layer's origin by that:

NSRange match = [[[self textView]text]rangeOfString:@"predict the future"];
NSRange glyphRange = [manager glyphRangeForCharacterRange:match actualCharacterRange:NULL];

CGRect textRect = [manager boundingRectForGlyphRange:glyphRange inTextContainer:[[self textView]textContainer]];

CGPoint textViewOrigin = self.textView.frame.origin;
textRect.origin.x += (textViewOrigin.x / 2);
textRect.origin.y += (textViewOrigin.y / 2);


CALayer* roundRect = [CALayer layer];
[roundRect setFrame:textRect];
[roundRect setBounds:textRect];

[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];

I get the following result if I move the text field, or if I don't divide the offsets by 2: The layer frame is off

I'd like to know if i'm on the right track and also how to find the NSTextContainer object's origin if so.

2

There are 2 answers

5
Jesús A. Álvarez On BEST ANSWER

To position the layer correctly, you only have to add self.textView.textContainerInset.top to textRect.origin.y, not the text view's origin.

But as I said in the comment, it won't work nicely if your match is across two lines. You may want to set the background colour of the matched range to highlight it, (using the attributedText property), but then you can't add the rounded corners or shadow.

3
Myron Slaw On

[textView textContainerInset]

Using the origin of the text view will not work because the insets may be changed somewhere else. An example would be if the parent view controller’s automaticallyAdjustsScrollViewInsets property is YES, or some custom text container layout is going on.

UIEdgeInsets textContainerInset = [[self textView]textContainerInset];
textRect.origin.x += textContainerInset.left;
textRect.origin.y += textContainerInset.top;

This is a solution for getting the geometry correct, but not if the text spans two lines.