15

I am working on a story app.Where We need to provide quizes. Now I am having a story and there are some blanks or hidden words over that story. Whenever I click over that hidden word,I will get the 4 options to answer that. I tried by placing button over the words,But that would be only when I am using some static position. I just want to know how can I get the frame of that word,which I need to hide ,so that I can place some button over that and can hide this.

You can see the image below..enter image description here All answers would be appreciated

Solution:- This will work after iOS 5 only not below that !

- (CGRect)frameOfTextRange:(NSRange)range inTextView:(UITextView *)textView
{
    UITextPosition *beginning = textView.beginningOfDocument; 
    UITextPosition *start = [textView positionFromPosition:beginning offset:range.location];
    UITextPosition *end = [textView positionFromPosition:start offset:range.length];
    UITextRange *textRange = [textView textRangeFromPosition:start toPosition:end];
    CGRect rect = [textView firstRectForRange:textRange]; 
    return [textView convertRect:rect fromView:textView.textInputView];



}

Thanks

See one more image for errors: enter image description here

Sabby
  • 2,586
  • 2
  • 27
  • 41

4 Answers4

19

UITextView adopts the UITextInput protocol. That protocol has the method -firstRectForRange: which will tell you the rectangle covering a range of characters. If the range of characters spans multiple lines, you have to call it repeatedly. The first time it will give you the first rect and tell you what range that covers. Then, you adjust the range you're asking about to be the remaining characters you're interested in and repeat.

Ken Thomases
  • 88,520
  • 7
  • 116
  • 154
  • Can you explain more or any examples as how to use this or some tutorial ,As i dont have any idea how to use that...If you can put me in some right direction further...I will appriciate that... – Sabby Apr 25 '12 at 15:05
  • 1
    See the answer to [this question](http://stackoverflow.com/questions/9126709/create-uitextrange-from-nsrange). I'm not sure if the `-convertRect:fromView:` call in that answer is appropriate for your case. – Ken Thomases Apr 25 '12 at 15:44
  • Fine Ken...I will check and let you know...Thanks Man – Sabby Apr 26 '12 at 09:26
  • I tried this method..but it is showing me many errors there, even I had tried the same answer from somewhere that has the errors as well...So could you clarify as well... – Sabby Apr 26 '12 at 12:27
  • Update your question with what you tried and how it failed. Be specific. – Ken Thomases Apr 26 '12 at 14:57
  • Hi Ken I have updated above ,please do check and let me know what I am missing or doing wrong. Thanks – Sabby Apr 27 '12 at 11:47
  • Strange. What iOS SDK are you targeting? You imported the framework header (e.g. `#import `), right? You can try replacing the dot syntax with accessor calls like `[textView beginningOfDocument]`. – Ken Thomases Apr 27 '12 at 20:26
  • I have tried by removing dot notation....and that gave me warning ,But other lines are showing errors as well....What could be the issue then.. and base ios SDk is 4.2 – Sabby Apr 28 '12 at 18:09
  • What warning did it give you? Show it and the line of code to which it refers exactly. – Ken Thomases Apr 28 '12 at 18:13
  • I have updated my question and I have written the Erro to the corresponding line before.Please check to the right of every line of code above.Please have a look...Thanks – Sabby Apr 29 '12 at 07:42
  • But you said you tried removing the use of dot syntax in favor of calling accessors explicitly and got different warnings. That's not what I see above. – Ken Thomases Apr 29 '12 at 16:01
  • Hi Ken ,I have uploaded one more image which shows errors and warnings.Sorry for delay,i was out of city...I am waiting for reply...Thanks – Sabby May 03 '12 at 12:39
  • I'm not sure what to tell you. `UITextView` really ought to declare that it responds to those messages. I ask again: are you sure you imported the proper headers? – Ken Thomases May 03 '12 at 13:05
  • I have imported #import now only..in my .h file...Is there any other header I need to include,Or is there any other framework I need to include.... – Sabby May 03 '12 at 13:19
  • I found the reason,the reason is that it only works in ios 5 with sdk 4...Thanks though..I have one more question...If I need to get the range of second same word in the textview then how would I go with that..because the above code is i use with textview range it gives me range of first coming word... – Sabby May 13 '12 at 13:58
  • For the code you've shown, you supply the `range` of characters and it gives you a rectangle. If you want the rectangle for a different word, you need to supply a different range of characters which correspond to the word you want. You didn't show how you calculate the range for a desired word, so I can't suggest what to do differently. – Ken Thomases May 13 '12 at 17:31
  • Hi Ken I am using this NSRange myrange=[myTextview.text rangeofText:@"sabby"]; ,This is how I am using,But suppose sabby has 3 occurances,Then how to get the rect and range for the second or third sabby. – Sabby May 13 '12 at 17:33
  • I assume you mean `-[NSString rangeOfString:]`. If so, then simply use one of the other `-rangeOfString:...` methods which take a range to search within, specifying the remainder of the string after the range you already found. Like `myrange = [myTextview.text rangeOfString:@"sabby" options:0 range:NSMakeRange(myrange.location + myrange.length, myTextview.text.length - (myrange.location + myrange.length))];`. – Ken Thomases May 13 '12 at 17:39
  • Thank ken even I was reading this thing,I just need to check how to provide this range location or how would this work....Thanks again – Sabby May 13 '12 at 17:56
  • You have calculated this thing NSMakeRange(myrange.location + myrange.length, myTextview.text.length - (myrange.location + myrange.length)),which word would this specify,2nd or 3rd and how this calculates...thanks – Sabby May 13 '12 at 17:58
  • It finds the *next* matching word. `myrange` is assumed to contain the range of the last matching word. Add its location and its length and you get the position immediately following that last match. The `NSMakeRange(...)` creates a range representing the part of `myTextview.text` which follows the last match. Then, `-rangeOfString:options:range:` is used to search only within that range for the next match. – Ken Thomases May 13 '12 at 18:11
  • Thanks Ken,I will practice on this.. lets see how much I dive and get the perfection... – Sabby May 13 '12 at 18:24
  • Oh But it is showing me exception...Range or index out of bounds...I think need to calculate it properly...Index is out of bounds..Thanks – Sabby May 13 '12 at 18:36
  • Add your code to the question, or maybe start a new question. – Ken Thomases May 13 '12 at 18:44
  • Is there a reason the UITextInput protocol requires so many methods? Do I have to implement them all (or can I delegate some away)? – atreat Apr 17 '13 at 01:54
2
-(void)textViewDidChangeSelection:(UITextView *)textView
 {
  NSRange range = textView.selectedRange;
 if(range.location<textView.text.length)
  {
    NSString * firstHalfString = [txtView.text substringToIndex:range.location];

    NSString *temp = @"s";
    CGSize s1 = [temp sizeWithFont:[UIFont systemFontOfSize:15] 
                          constrainedToSize:CGSizeMake(self.view.bounds.size.width - 40, MAXFLOAT)  // - 40 For cell padding
                              lineBreakMode:UILineBreakModeWordWrap]; // enter you textview font size

    CGSize s = [firstHalfString sizeWithFont:[UIFont systemFontOfSize:15] 
                           constrainedToSize:CGSizeMake(self.view.bounds.size.width - 40, MAXFLOAT)  // - 40 For cell padding
                               lineBreakMode:UILineBreakModeWordWrap]; // enter you textview font size


    //Here is the frame of your word in text view.
    NSLog(@"xcoordinate=%f, ycoordinate =%f, width=%f,height=%f",s.width,s.height,s1.width,s1.height);

     CGRect rectforword = CGRectMake(s.width, s.height, s1.width, s1.height);
    // rectforword is rect of yourword


    }
    else
    {
        // Do what ever you want to do

     }   
}

>>>Edited...

This method is call when you select or tap on the textview text but you can use this method in any of UITextView Delegate Method

Hope, this will help you...enjoy

Nitin
  • 7,455
  • 2
  • 32
  • 51
  • Thanks for this...But I have one problem,I have checked this solution before and your method would be called when i touch textview,But I need to place the controls or buttons before,and on select i need to show the list of options..Then how to do that...You can see the image above as well – Sabby Apr 25 '12 at 15:03
  • you can do it easily using my code..anyway tonight i have some work so will workout it by tomorrow. – Nitin Apr 25 '12 at 15:10
  • Oh thanks Nit...I will wait for your help...Really appreciate – Sabby Apr 26 '12 at 09:25
  • Hi Nit,are you free now,I am really in need of this solution.Please try to help me out..I am waiting thanks – Sabby May 03 '12 at 12:40
  • I am free but your scenario need to workout. Right now i don't have so much time than after i will try and will tell you if will make it.. – Nitin May 03 '12 at 12:45
  • You try continue. i can say in any case you need to use above code for such type of scenario. – Nitin May 03 '12 at 12:47
2

Following on from Ken Thomases' answer, from iOS 6 and onwards the UITextInput protocol includes the following method:

- (NSArray *)selectionRectsForRange:(UITextRange *)range

(See the reference doc).

The result is an array of UITextSelectionRects, which have a bunch of information about selection ranges in text... Depending on how you want to use the rects of text-chunks, the above method might be useful.

(UITextSelectionRect reference).

Note: from my usage with UITextView, the array of UITextSelectionRects returned contains, what might be interpreted as, two additional selection rects. These are the last two selection rects in the array and I assume they correspond to the start and end positions of the selection. These selection rects each have a width of 0 and the containsStart / containsEnd properties are set accordingly.

Gavin Hope
  • 2,173
  • 24
  • 38
0

In my case adding the "layoutIfNeeded" helped.

    textView.superview?.layoutIfNeeded()
    let beginning = textView.beginningOfDocument
    let start = textView.position(from: beginning, offset: range.location)
    let end = textView.position(from: start!, offset: range.length)
    let textRange = textView.textRange(from: start!, to: end!)
    let frame = textView.firstRect(for: textRange!)
aqsa arshad
  • 801
  • 8
  • 27