2014-04-02 59 views
10

爲了支持UIAccessibilityReadingContent協議,我需要我的UITextView來回答有關其線路的問題。這些協議的,我需要實現的方法:從UITextView和NSLayoutManager獲取線路信息

  • accessibilityLineNumberForPoint: < - 提供了一個座標,返回行號
  • accessibilityContentForLineNumber: < - 返回給定行的文本
  • accessibilityFrameForLineNumber: < - 鑑於一個行號,返回其框架
  • accessibilityPageContent < - 整個文本內容。我有。 :)

我認爲,NSLayoutManager可以幫助我,但我沒有那種經驗。我想到了一些(我認爲),但仍需要一些幫助。

蘋果有一些示例代碼(here),可以讓我的行數在文本視圖:

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

我想憑上述lineRange,我可以計算行rects使用這種方法對NSLayoutManager

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

並給予lineRanges我應該能夠計算使用一個點的行號(通過尋找包含字形指數lineRange

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

所以剩下的是,如何得到一行的內容(作爲NSString),給定一個行號?

+0

你確定你需要這個協議,通常你可以設置NSTextStorage,NSLayoutManager和NSTextContainer,一切都會好的。我讀了關於它的好主題:http://www.raywenderlich.com/50151/text-kit-tutorial。 – kaspartus

+0

不幸的是。在啓用VoiceOver時,UITextView似乎不會逐行讀出。至少不是在我的實現中(嵌入在UITableViewCells中的UITextViews) –

+0

'NSLayoutManager'提供了與glyph範圍一起工作的方法,以及characer範圍的方法。最後有兩種方法允許你在這兩個範圍之間進行轉換:' - [NSLayoutManager glyphRangeForCharacterRange:actualCharacterRange:]'和' - [NSLayoutManager characterRangeForGlyphRange:actualGlyphRange:]''。要檢索字符串,只需將您感興趣的glyphRange轉換爲characterRange,然後就可以從'UITextView'的'textStorage'使用'attributedSubstringFromRange:'或'string'和'substringWithRange:'來檢索一個子字符串。 – Dalzhim

回答

4

在一個簡單的解決方案在想,這裏是重現你需要

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

請看看屬性有什麼小碼:

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

你可以在你的類以下以創建此屬性:

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

我建議您將分析呼叫添加到followi NG代表:

- (void)textViewDidChange:(UITextView *)textView 

在那裏,你可以例如分析後得到的2號線的框架只是做:self.frames [1]

或獲取第二行做的文字:[textView.text substringWithRange:[self.ranges [1] rangeValue]]

例如是這樣的:

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

擁有中的所有幀self.frames我認爲你可以輕鬆地做其他事情,使用座標猜測行數。

+0

我在你的漂亮解決方案中發現了一個小錯誤,你應該使用'index = NSMaxRange(tmpRange);'而不是'index = NSMaxRange(range);'來獲得正確的行數。運行在9.3。否則,解決方案是完美的 - 加上一個給你! :-) –