2012-02-14 19 views
10

我的目標是在UITextView中標記所有可見拼寫錯誤的單詞。如何在UITextView中有效地查找可見詞的CGRects?

效率低下的算法是使用拼寫檢查器查找文本中拼寫錯誤的單詞的所有範圍,使用positionFromPosition:inDirection:offset等將它們轉換爲UITextRange對象,然後使用UITextInput方法firstRectFromRange獲取圖形rects。

因此所有的文字 - >拼錯words-> NSRange收集 - > UITextRange收集 - >收集的CGRect - >評估的知名度,繪製可見那些

的問題是,這要求所有的文字被選中,並且所有拼錯的單詞都轉換爲圖形矩形。因此,我想要走的路是以某種方式找出UITextView中底層文本的哪些部分,此時可見。

因此,對於文本可見的範圍 - >拼錯words-> NSRange收集 - > UITextRange收集 - >收集的CGRect - >評估的知名度,繪製可見那些

ios - how to find what is the visible range of text in UITextView?的代碼可能工作,以此來約束要檢查哪些文本部分,但仍要求所有文本都是測量的,我想這可能會相當昂貴。

有什麼建議嗎?

回答

18

由於UITextViewUIScrollView的一個子類,它的bounds屬性反映了它的座標系的可見部分。所以像這樣的東西應該工作:

- (NSRange)visibleRangeOfTextView:(UITextView *)textView { 
    CGRect bounds = textView.bounds; 
    UITextPosition *start = [textView characterRangeAtPoint:bounds.origin].start; 
    UITextPosition *end = [textView characterRangeAtPoint:CGPointMake(CGRectGetMaxX(bounds), CGRectGetMaxY(bounds))].end; 
    return NSMakeRange([textView offsetFromPosition:textView.beginningOfDocument toPosition:start], 
     [textView offsetFromPosition:start toPosition:end]); 
} 

這假設從上到下,從左到右的文字佈局。如果你想使它適用於其他佈局方向,你將不得不加倍努力。 :)

+0

尼斯。爲了提高效率,通過從頭開始移動長度字符來發現結局 - 從文檔的開頭開始一直很慢,但提前便宜。 – 2012-02-17 10:12:21

+0

當你說,「這樣的事情應該工作」,你真的嘗試過嗎?這幾乎是我實際可視文本範圍的三倍。謝謝。 – 2014-08-01 15:56:43

+1

@JasonTyler [這是一個包含測試應用程序的回購。](https://github.com/mayoff/textview-visible-range)對我很好用。可能需要Xcode 6。 – 2014-08-01 16:48:34

3

羅布的答案,寫在斯威夫特。我已經添加了一些安全檢查。

private func visibleRangeOfTextView(textView: UITextView) -> NSRange { 
    let bounds = textView.bounds 
    let origin = CGPointMake(10,10) //Overcome the default UITextView left/top margin 
    let startCharacterRange = textView.characterRangeAtPoint(origin) 
    if startCharacterRange == nil { 
     return NSMakeRange(0,0) 
    } 
    let startPosition = textView.characterRangeAtPoint(origin)!.start 

    let endCharacterRange = textView.characterRangeAtPoint(CGPointMake(CGRectGetMaxX(bounds), CGRectGetMaxY(bounds))) 
    if endCharacterRange == nil { 
     return NSMakeRange(0,0) 
    } 
    let endPosition = textView.characterRangeAtPoint(CGPointMake(CGRectGetMaxX(bounds), CGRectGetMaxY(bounds)))!.end 

    let startIndex = textView.offsetFromPosition(textView.beginningOfDocument, toPosition: startPosition) 
    let endIndex = textView.offsetFromPosition(startPosition, toPosition: endPosition) 
    return NSMakeRange(startIndex, endIndex) 
} 

更新了夫特4:

private func visibleRangeOfTextView(textView: UITextView) -> NSRange { 
    let bounds = textView.bounds 
    let origin = CGPoint(x: 10, y: 10) //Overcome the default UITextView left/top margin 
    let startCharacterRange = textView.characterRange(at: origin) 
    if startCharacterRange == nil { 
     return NSRange(location: 0, length: 0) 
    } 
    let startPosition = textView.characterRange(at: origin)?.start 

    let endCharacterRange = textView.characterRange(at: CGPoint(x: bounds.maxX, y: bounds.maxY)) 
    if endCharacterRange == nil { 
     return NSRange(location: 0, length: 0) 
    } 
    let endPosition = textView.characterRange(at: CGPoint(x: bounds.maxX, y: bounds.maxY))!.end 

    let startIndex = textView.offset(from: textView.beginningOfDocument, to: startPosition!) 
    let endIndex = textView.offset(from: startPosition!, to: endPosition) 
    return NSRange(location: startIndex, length: endIndex) 
} 

實施例的使用,從一個按鈕抽頭稱爲:

@IBAction func buttonTapped(sender: AnyObject) { 
    let range = visibleRangeOfTextView(self.textView) 

    // Note: "as NSString" won't work correctly with Emoji and stuff, 
    // see also: http://stackoverflow.com/a/24045156/1085556 
    let nsText = self.textView.text as NSString 
    let text = nsText.substringWithRange(range) 
    NSLog("range: \(range), text = \(text)")   
} 
相關問題