2014-04-02 17 views
10

Để hỗ trợ giao thức UIAccessibilityReadingContent, tôi cần UITextView của tôi trả lời cho tôi các câu hỏi về các dòng của nó. Đây là những phương pháp của giao thức mà tôi cần phải thực hiện:Lấy thông tin về dòng từ UITextView và NSLayoutManager

  • accessibilityLineNumberForPoint: < - Cung cấp một phối hợp, trả lại một số dòng
  • accessibilityContentForLineNumber: < - Trả lại văn bản của một đường thẳng cho trước
  • accessibilityFrameForLineNumber: < - Với một số dòng, trả lại khung của nó
  • accessibilityPageContent < - Toàn bộ nội dung văn bản. Mà tôi có. :)

Tôi cho rằng NSLayoutManager có thể giúp tôi, nhưng tôi không có kinh nghiệm với nó. Tôi đã tìm ra một số (tôi nghĩ), nhưng vẫn cần một số trợ giúp.

Apple có một số mẫu mã (here) có thể làm cho tôi số dòng trong giao diện văn bản:

NSLayoutManager *layoutManager = [textView layoutManager]; 
unsigned numberOfLines, index, numberOfGlyphs = 
     [layoutManager numberOfGlyphs]; 
NSRange lineRange; 
for (numberOfLines = 0, index = 0; index < numberOfGlyphs; numberOfLines++){ 
    (void) [layoutManager lineFragmentRectForGlyphAtIndex:index 
      effectiveRange:&lineRange]; 
    index = NSMaxRange(lineRange); 
} 

Tôi hình dung rằng với lineRange trên, tôi có thể tính toán dòng dễ phân biệt bằng phương pháp này trên NSLayoutManager :

- (NSRect)boundingRectForGlyphRange:(NSRange)glyphRange inTextContainer:(NSTextContainer *)container 

Và cho lineRanges tôi nên có thể tính toán số dòng cho một điểm sử dụng (bằng cách tìm các lineRange có chứa chỉ số glyph:

- (NSUInteger)glyphIndexForPoint:(CGPoint)point inTextContainer:(NSTextContainer *)container fractionOfDistanceThroughGlyph:(CGFloat *)partialFraction 

Vì vậy, phần còn lại là gì, làm cách nào để lấy nội dung của một dòng (như là NSString), được cung cấp một số dòng?

+0

Bạn có chắc chắn rằng bạn cần giao thức đó, trong trường hợp phổ biến bạn chỉ có thể đặt NSTextStorage, NSLayoutManager và NSTextContainer và mọi thứ sẽ ổn. Tôi đọc chủ đề tuyệt vời về nó: http://www.raywenderlich.com/50151/text-kit-tutorial. – kaspartus

+0

Thật không may là có. UITextView dường như không cung cấp từng dòng đọc ra khỏi hộp khi VoiceOver được bật. Ít nhất là không phải trong thực hiện của tôi (UITextViews nhúng trong UITableViewCells) –

+0

'NSLayoutManager' cung cấp các phương thức làm việc với các phạm vi glyph, cũng như các phương thức cho các phạm vi characer. Cuối cùng có hai phương thức cho phép bạn chuyển đổi giữa hai phạm vi đó: '- [NSLayoutManager glyphRangeForCharacterRange: actualCharacterRange:]' và '- [NSLayoutManager characterRangeForGlyphRange: actualGlyphRange:]'. Để lấy chuỗi, chỉ cần chuyển đổi glyphRange mà bạn quan tâm thành một characterRange, sau đó bạn có thể lấy một chuỗi con từ 'textStorage' của' UITextView' bằng cách sử dụng 'attributedSubstringFromRange:' hoặc cả 'string' và' substringWithRange: '. – Dalzhim

Trả lời

4

suy nghĩ trong một giải pháp dễ dàng, đây là một mã nhỏ mà sinh sản những gì bạn cần

- (void)analyse:(UITextView *)textView 
{ 
    NSLayoutManager *layoutManager = [textView layoutManager]; 
    NSString *string = textView.text; 
    unsigned numberOfLines, index, stringLength = [string length]; 

    NSMutableArray *ranges = [NSMutableArray new]; 
    NSMutableArray *frames = [NSMutableArray new]; 
    for (index = 0, numberOfLines = 0; index < stringLength; numberOfLines++) 
    { 
     NSRange tmprange; 
     NSRange range = [string lineRangeForRange:NSMakeRange(index, 0)]; 
     CGRect rect = [layoutManager lineFragmentRectForGlyphAtIndex:index 
              effectiveRange:&tmprange]; 

     [ranges addObject:[NSValue valueWithRange:range]]; 

     [frames addObject:[NSValue valueWithCGRect:rect]]; 
     index = NSMaxRange(range); 
    } 
    self.ranges = ranges; 
    self.frames = frames; 
    self.numberOfLines = numberOfLines; 
} 

Hãy xem các thuộc tính:

self.ranges = ranges; 
self.frames = frames; 
self.numberOfLines = numberOfLines; 

Bạn có thể có những điều sau đây trong lớp học của bạn để tạo thuộc tính này:

@property (nonatomic) NSInteger numberOfLines; 
@property (strong, nonatomic) NSArray *ranges; 
@property (strong, nonatomic) NSArray *frames; 

Tôi đề nghị bạn thêm cuộc gọi phân tích bên trong followi ng đại biểu:

- (void)textViewDidChange:(UITextView *)textView 

Ở đó bạn có thể ví dụ như sau khi phân tích có được khung của dòng thứ 2 chỉ thực hiện: self.frames [1]

Hoặc nhận được văn bản của dòng thứ hai thực hiện: [textView.text substringWithRange: [self.ranges [1] rangeValue]]

Ví dụ như thế này:

if (self.numberOfLines > 1) 
{ 
    NSRange range = [self.ranges[1] rangeValue]; 
    NSLog(@"2nd line = %@", [textView.text substringWithRange:range]); 
    NSLog(@"2nd line frame = %@", self.frames[1]); 
} 

Có tất cả các khung trong self.frames Tôi nghĩ bạn có thể dễ dàng thực hiện việc khác, đoán số dòng sử dụng tọa độ.

+0

Tôi tìm thấy sai lầm nhỏ trong giải pháp đẹp của bạn, bạn nên sử dụng 'index = NSMaxRange (tmpRange);' thay vì 'index = NSMaxRange (range);' để có được số dòng chính xác. Chạy trên 9.3. Nếu không, giải pháp là hoàn hảo - cộng thêm một cho bạn! :-) –

Các vấn đề liên quan