2012-02-14 39 views
10

Mục tiêu của tôi là đánh dấu tất cả các từ viết sai chính tả có thể nhìn thấy trong UITextView.Làm thế nào để tìm kiếm hiệu quả CGRects cho các từ hiển thị trong UITextView?

Thuật toán không hiệu quả là sử dụng trình kiểm tra chính tả để tìm tất cả các từ sai chính tả trong văn bản, chuyển đổi chúng thành các đối tượng UITextRange bằng cách sử dụng positionFromPosition: inDirection: offset etc, sau đó lấy các đồ họa bằng cách sử dụng phương thức UITextInput firstRectFromRange.

Như vậy tất cả các văn bản -> sai chính tả words-> Bộ sưu tập NSRange -> Bộ sưu tập UITextRange -> Bộ sưu tập CGRect -> đánh giá cho tầm nhìn, vẽ những có thể nhìn thấy

Vấn đề là điều này đòi hỏi rằng tất cả các văn bản được kiểm tra, và tất cả các từ sai chính tả được chuyển đổi thành các đồ họa.

Vì vậy, tôi tưởng tượng con đường để đi là bằng cách nào đó tìm hiểu những gì các bộ phận của .text tiềm ẩn trong UITextView đó là nhìn thấy được vào lúc này.

Như vậy cho hàng loạt các văn bản rõ ràng -> sai chính tả words-> Bộ sưu tập NSRange -> Bộ sưu tập UITextRange -> CGRect bộ sưu tập -> đánh giá cho tầm nhìn, vẽ những có thể nhìn thấy

Các mã trong ios - how to find what is the visible range of text in UITextView? có thể làm việc như một cách để ràng buộc phần nào của văn bản cần kiểm tra, nhưng vẫn yêu cầu tất cả văn bản được đo lường, điều tôi tưởng tượng có thể khá tốn kém.

Mọi đề xuất?

Trả lời

18

UITextView là một phân lớp của UIScrollView, thuộc tính bounds phản ánh phần hiển thị của hệ tọa độ của nó. Vì vậy, một cái gì đó như thế này nên làm việc:

- (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]); 
} 

này giả định một cách bố trí văn bản từ trên xuống dưới, từ trái sang phải. Nếu bạn muốn làm cho nó làm việc cho các hướng bố trí khác, bạn sẽ phải làm việc chăm chỉ hơn. :)

+0

Nice. Để có hiệu quả, hãy tìm kết thúc bằng cách di chuyển các ký tự có độ dài chuyển tiếp từ đầu - chỉ ra rằng nó chậm đi từ đầu trong tài liệu, nhưng rẻ tiền để thăng tiến. –

+0

Khi bạn nói, "một cái gì đó như thế này sẽ làm việc", có bạn thực sự đã thử nó? Điều này đang trở lại gần gấp ba lần phạm vi của văn bản trực quan thực tế đối với tôi. Cảm ơn. –

+1

@JasonTyler [Đây là một repo có chứa một ứng dụng thử nghiệm.] (Https://github.com/mayoff/textview-visible-range) Hoạt động tuyệt vời cho tôi. Có thể yêu cầu Xcode 6. –

3

câu trả lời của Rob, viết bằng Swift. Tôi đã thêm một số kiểm tra an toàn.

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) 
} 

Cập nhật cho Swift 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) 
} 

Ví dụ sử dụng, được gọi từ một nút tap:

@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)")   
} 
Các vấn đề liên quan