web-dev-qa-db-fra.com

Remplacer le texte UITextViews par une chaîne attribuée

J'ai une UITextView et lorsque l'utilisateur entre du texte, je souhaite formater le texte à la volée. Quelque chose comme mise en évidence de la syntaxe ...

Pour cela, j'aimerais utiliser UITextView...

Tout fonctionne bien, attendez-vous à un problème: je prends le texte de la vue texte et en fais un NSAttributedString. Je modifie cette chaîne attribuée et la redéfinis en tant que textView.attributedText.

Cela se produit chaque fois que l'utilisateur tape. Je dois donc me souvenir de la selectedTextRange avant la modification de la attributedText et la remettre ensuite pour que l'utilisateur puisse continuer à taper à l'endroit où il était en train de taper auparavant. Le seul problème est qu'une fois que le texte est suffisamment long pour nécessiter un défilement, la UITextView commence maintenant à défiler vers le haut si je tape lentement.

Voici un exemple de code:

- (void)formatTextInTextView:(UITextView *)textView
{
  NSRange selectedRange = textView.selectedRange;
  NSString *text = textView.text;

  // This will give me an attributedString with the base text-style
  NSMutableAttributedString *attributedString = [self attributedStringFromString:text];

  NSError *error = nil;
  NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"#(\\w+)" options:0 error:&error];
  NSArray *matches = [regex matchesInString:text
                                    options:0
                                      range:NSMakeRange(0, text.length)];

  for (NSTextCheckingResult *match in matches)
  {
    NSRange matchRange = [match rangeAtIndex:0];
    [attributedString addAttribute:NSForegroundColorAttributeName
                             value:[UIColor redColor]
                             range:matchRange];
  }

  textView.attributedText = attributedString;
  textView.selectedRange = selectedRange;
}

Existe-t-il une solution sans utiliser CoreText directement? J'aime la capacité de UITextViews à sélectionner du texte, etc.

14
Georg

Je ne suis pas sûr que ce soit la solution correcte, mais cela fonctionne.
Désactivez simplement le défilement avant de formater le texte et activez-le après le formatage

- (void)formatTextInTextView:(UITextView *)textView
{
    textView.scrollEnabled = NO;
    NSRange selectedRange = textView.selectedRange;
    NSString *text = textView.text;

    // This will give me an attributedString with the base text-style
    NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:text];

    NSError *error = nil;
    NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"#(\\w+)" options:0 error:&error];
    NSArray *matches = [regex matchesInString:text
                                      options:0
                                        range:NSMakeRange(0, text.length)];

    for (NSTextCheckingResult *match in matches)
    {
        NSRange matchRange = [match rangeAtIndex:0];
        [attributedString addAttribute:NSForegroundColorAttributeName
                                 value:[UIColor redColor]
                                 range:matchRange];
    }

    textView.attributedText = attributedString;
    textView.selectedRange = selectedRange;
    textView.scrollEnabled = YES;
}
36
Sergey Kuryanov

J'ai utilisé la réponse de Sergeys moi-même et l'ai portée dans Swift 2:

func formatTextInTextView(textView: UITextView) {
    textView.scrollEnabled = false
    let selectedRange = textView.selectedRange
    let text = textView.text

    // This will give me an attributedString with the base text-style
    let attributedString = NSMutableAttributedString(string: text)

    let regex = try? NSRegularExpression(pattern: "#(\\w+)", options: [])
    let matches = regex!.matchesInString(text, options: [], range: NSMakeRange(0, text.characters.count))

    for match in matches {
        let matchRange = match.rangeAtIndex(0)
        attributedString.addAttribute(NSForegroundColorAttributeName, value: UIColor.redColor(), range: matchRange)
    }

    textView.attributedText = attributedString
    textView.selectedRange = selectedRange
    textView.scrollEnabled = true
}
4
Tapani

Dans Swift 4:

func createAttributedText() {
    let stringText = "Test String"
    let stringCount = stringText.count
    let string: NSMutableAttributedString = NSMutableAttributedString(string: stringText)

    string.addAttribute(NSForegroundColorAttributeName, value: UIColor.red, range: NSMakeRange(0, stringCount))

    self.textView.attributedText =  string
}
0
fugu2

Swift 2.0:

let myDisplayTxt:String = "Test String"

    let string: NSMutableAttributedString = NSMutableAttributedString(string: self.myDisplayTxt)
    string.addAttribute(NSForegroundColorAttributeName, value: UIColor.redColor(), range: NSMakeRange(0, 5))
    string.addAttribute(String(kCTForegroundColorAttributeName), value: UIColor.redColor().CGColor as AnyObject, range: NSMakeRange(0, 5))

    self.sampleTextView.attributedText =  string
0
A.G