2010-04-13 125 views
21

有没有办法在UITextView中获取光标(闪烁条)的位置(CGPoint)(最好是相对于其内容)。我不是说这个位置是一个NSRange。我需要一些东西:光标在UITextView中的像素位置

- (CGPoint)cursorPosition; 

它应该是一个非私有的API方式。

+0

你说的是文字插入点吗?一世。e闪烁的垂直条? – 2010-04-13 21:41:37

+0

是的,这就是我的意思。 – 2010-04-15 18:11:58

+0

没有公开的方法来获取该信息。你想达到什么目的?可能有另一种方法。 – 2010-04-13 21:47:32

回答

10

这很痛苦,但您可以使用UIStringDrawing添加到NSString来做到这一点。下面是我使用的通用算法:

CGPoint origin = textView.frame.origin; 
NSString* head = [textView.text substringToIndex:textView.selectedRange.location]; 
CGSize initialSize = [head sizeWithFont:textView.font constrainedToSize:textView.contentSize]; 
NSUInteger startOfLine = [head length]; 
while (startOfLine > 0) { 
    /* 
    * 1. Adjust startOfLine to the beginning of the first word before startOfLine 
    * 2. Check if drawing the substring of head up to startOfLine causes a reduction in height compared to initialSize. 
    * 3. If so, then you've identified the start of the line containing the cursor, otherwise keep going. 
    */ 
} 
NSString* tail = [head substringFromIndex:startOfLine]; 
CGSize lineSize = [tail sizeWithFont:textView.font forWidth:textView.contentSize.width lineBreakMode:UILineBreakModeWordWrap]; 
CGPoint cursor = origin; 
cursor.x += lineSize.width; 
cursor.y += initialSize.height - lineSize.height; 
return cursor; 
} 

我以前[NSCharacterSet whitespaceAndNewlineCharacterSet]找字边界。

这也可以做到(大概更有效)的CoreText使用CTFrameSetter,但不是在iPhone OS 3.1.3可用,因此,如果您所指定的iPhone,你需要坚持UIStringDrawing

+1

这是一个很好的解决方法,我也玩过。 要找到字边界,我发现最好使用CFStringTokenizer。 您的实现不会给出x和y坐标,而是包含插入符号的行中字符的大小,直到插入符号为止,对吗? 但是,我接受你的方法作为答案,因为我最终采取了类似于我的需求的方法。 – 2010-05-12 17:25:49

+0

感谢关于CFStringTokenizer的指针,我忽略了这一点。从initialSize.height中减去lineSize.height将为您提供游标的y偏移量(相对于UITextView),最后一行代码的宽度为您提供x偏移量。 – Tony 2010-05-17 17:15:38

+0

您可以详细说明一下 /* * 1.将startOfLine调整为startOfLine之前的第一个单词的开头 * 2.检查绘制头部的子字符串startOfLine是否导致高度减小与initialSize相比。 * 3.如果是这样,那么你已经确定了包含光标的行的开始,否则继续前进。 */ 我还需要在UITextView中的光标位置。 – tek3 2010-06-15 13:18:52

3

是的 - 就像有一种获取光标位置的方法一样。只需使用

CGRect caretRect = [textView rectContainingCaretSelection]; 
return caretRect.origin; 

否 - 在此方法中是私人的。这没有公共API。

+0

这个方法确实是我搜索的内容,但我当然不能使用私有API。其他方案? – 2010-04-15 18:13:40

+2

在iOS 4.2中似乎不存在。我的UITextView中没有这样的选择器异常。 – mxcl 2011-01-20 14:34:28

1

我尝试标记一个选定的文本,即我收到一个NSRange并且想在该文本后面画一个黄色矩形。有另一种方法吗?

我可以告诉你一些诀窍:

NSRange selectedRange = myTextView.selectedRange; 
[myTextView select:self]; 
UIMenuController* sharedMenu = [UIMenuController sharedMenuController]; 
CGRect menuFrame = [sharedMenu menuFrame]; 
[sharedMenu setMenuVisible:NO]; 
myTextView.selectedRange = selectedRange 

使用此代码,就可以知道得到剪切/复制/粘贴菜单的位置,并有把你的黄色矩形。

我没有找到一种方法来获取菜单位置,强迫它出现在模拟选择操作。

问候 Assayag

+0

我实现了这个测试,这是一个很好的黑客,但实际上没有用,因为你不能从menuFrame到光标位置(箭头向下而不是向上等问题)。 – 2010-09-07 18:42:01

1

采取的UITextView的屏幕截图,然后搜索像素数据匹配光标的颜色的颜色。

-(CGPoint)positionOfCursorForTextView:(UITextView)textView { 
    //get CGImage from textView 
    UIGraphicsBeginImageContext(textView.bounds.size); 
    [textView.layer renderInContext:UIGraphicsGetCurrentContext()]; 
    CGImageRef textImageRef = UIGraphicsGetImageFromCurrentImageContext().CGImage; 
    UIGraphicsEndImageContext(); 

    //get raw pixel data 
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 
    uint8_t * textBuffer = (uint8_t*)malloc(Width * Height * 4); 
    NSUInteger bytesPerRow = 4 * Width; 
    NSUInteger bitsPerComponent = 8; 
    CGContextRef context = CGBitmapContextCreate(textBuffer, Width, Height, 
              bitsPerComponent, bytesPerRow, colorSpace, 
              kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big); 


    CGColorSpaceRelease(colorSpace); 

    CGContextDrawImage(context, CGRectMake(0, 0, Width, Height), textImageRef); 
    CGContextRelease(context); 

    //search 

    for(int y = 0; y < Height; y++) 
    { 
     for(int x = 0; x < Width * 4; x += 4) 
     { 
      int red = textBuffer[y * 4 * (NSInteger)Width + x]; 
      int green = textBuffer[y * 4 * (NSInteger)Width + x + 1];  
      int blue = textBuffer[y * 4 * (NSInteger)Width + x + 2]; 
      int alpha = textBuffer[y * 4 * (NSInteger)Width + x + 3];  


      if(COLOR IS CLOSE TO COLOR OF CURSOR) 
      { 
       free(textBuffer); 
       CGImageRelease(textImageRef); 
       return CGPointMake(x/4, y); 
      } 
     } 
    } 

    free(textBuffer); 
    CGImageRelease(textImageRef); 
    return CGPointZero; 
} 
+7

Yay的创意答案,不容易出错和计算密集型。 – 2011-03-07 10:54:40

+0

你能告诉我什么是你的代码的宽度和高度? – 2011-03-11 10:11:35

+1

哇!!!!!它真的有不同的答案,为什么我投票给它。 – Tirth 2011-08-25 10:24:30

46

需要iOS 5

CGPoint cursorPosition = [textview caretRectForPosition:textview.selectedTextRange.start].origin; 

记住检查selectedTextRangenil调用此方法之前。您还应该使用selectedTextRange.empty来检查它是光标位置而不是文本范围的开头。所以:

if (textview.selectedTextRange.empty) { 
    // get cursor position and do stuff ... 
} 
+3

这仅限iOS 5。虽然-caretRectForPosition可用3.2及更高版本,但UITextView不符合UITextInput,直到iOS 5 – 2012-01-06 03:24:25

+0

感谢Jonathan,我已经更新了答案。 – Craz 2012-01-12 22:31:48

1

SWIFT 4版本:

if let cursorPosition = textView.selectedTextRange?.start { 
    // cursorPosition is a UITextPosition object describing position in the text (text-wise description) 

    let caretPositionRectangle: CGRect = textView.caretRect(for: cursorPosition) 
    // now use either the whole rectangle, or its origin (caretPositionRectangle.origin) 
} 

textView.selectedTextRange?.start返回光标的文本位置,然后我们简单地使用textView.caretRect(for:)来获得textView它的像素位置。