5

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.

Myron Slaw
  • 886
  • 9
  • 21

2 Answers2

8

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.

Jesús A. Álvarez
  • 2,958
  • 23
  • 22
  • +1 for the correct answer for the position issue (you beat me too it). I actually need to use a CALayer because I don't want to change attributes on the text, just to highlight search results. The set up the above code that way just to figure out how to get geometry from the text (a starting point) and get a layer drawn correctly. – Myron Slaw Dec 16 '13 at 00:10
  • also, the glyph range may not be the same as the character range with some characters, you should convert it with glyphRangeForCharacterRange:actualCharacterRange: – Jesús A. Álvarez Dec 16 '13 at 00:18
  • That's what I used to get the glyph range. Second line. – Myron Slaw Dec 16 '13 at 00:24
  • @Zydeco is there any way to add the rounder corners on the highlighted text when the matched text is across two lines? I am having this exact problem, the rect is being drawn incorrectly across two lines. – ilteris Dec 16 '13 at 16:48
  • I asked my question here: http://stackoverflow.com/questions/20689475/textkit-custom-text-attribute-draws-big-rect-when-it-spans-multiple-lines – ilteris Dec 19 '13 at 18:53
1

[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.

Myron Slaw
  • 886
  • 9
  • 21
  • Hi @Lone Gunman. Do you have any solution for the problem when text spans two lines? Currently it draws a big rect across two lines for me. – ilteris Dec 16 '13 at 16:51
  • i'm having issues with the double lines. Posted it in a new question: http://stackoverflow.com/questions/20694942/drawing-a-calayer-over-text-in-a-uitextview-which-span-multiple-lines – Myron Slaw Dec 20 '13 at 01:48
  • Found the solution for the double line issue: http://stackoverflow.com/questions/20694942/using-a-calayer-to-highlight-text-in-a-uitextview-which-spans-multiple-lines – Myron Slaw Dec 29 '13 at 06:39