Obtenir des informations de ligne de UITextView et NSLayoutManager

Afin de supporter le protocole UIAccessibilityReadingContent , j'ai besoin de mon UITextView pour répondre à mes questions sur ses lignes. Ce sont les methods du protocole que j'ai besoin de mettre en œuvre:

  • accessibilityLineNumberForPoint: <- Fourni une coordonnée, returnne un numéro de ligne
  • accessibilityContentForLineNumber: <- Retourne le text d'une ligne donnée
  • accessibilityFrameForLineNumber: <- Étant donné un numéro de ligne, returnne son cadre
  • accessibilityPageContent <- Tout le contenu du text. Que j'ai. 🙂

Je pense que NSLayoutManager peut m'aider, mais je n'en ai pas l'expérience. J'en ai compris quelques-uns (je pense), mais j'ai quand même besoin d'aide.

Apple a un exemple de code ( ici ) qui peut me donner le nombre de lignes dans la vue du text:

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

Je me lineRange qu'avec lineRange ci-dessus, je peux calculer les rects de ligne en utilisant cette méthode sur NSLayoutManager :

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

Et étant donné lineRanges je devrais être capable de calculer le numéro de ligne pour un point en utilisant (en trouvant le lineRange qui contient l'index glyphe:

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

Donc ce qui rest est, comment puis-je get le contenu d'une ligne (comme un NSSsortingng ), donné un numéro de ligne?

en pensant à une solution facile, voici un petit code qui reproduit ce dont vous avez besoin

 - (void)parsing:(UITextView *)textView { NSLayoutManager *layoutManager = [textView layoutManager]; NSSsortingng *ssortingng = textView.text; unsigned numberOfLines, index, ssortingngLength = [ssortingng length]; NSMutableArray *ranges = [NSMutableArray new]; NSMutableArray *frames = [NSMutableArray new]; for (index = 0, numberOfLines = 0; index < ssortingngLength; numberOfLines++) { NSRange tmprange; NSRange range = [ssortingng 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; } 

S'il vous plaît jeter un oeil des propriétés:

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

Vous pouvez avoir les éléments suivants dans votre class pour créer ces propriétés:

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

Je vous suggère d'append l'appel d'parsing dans le délégué suivant:

 - (void)textViewDidChange:(UITextView *)textView 

Vous pouvez par exemple après l'parsing get le cadre de la 2ème ligne en train de faire: self.frames [1]

Ou get le text de la deuxième ligne en train de faire: [textView.text subssortingngWithRange: [self.ranges [1] rangeValue]]

Par exemple comme ceci:

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

Ayant tous les frameworks dans self.frames je pense que vous pouvez facilement faire l'autre chose, devinez le numéro de ligne en utilisant une coordonnée.