54 votes

Créer UITextRange à partir de NSRange

J'ai besoin de trouver la trame de pixels pour différentes plages dans une vue de texte. J'utilise la fonction - (CGRect)firstRectForRange:(UITextRange *)range; pour le faire. Cependant, je n'arrive pas à trouver comment créer réellement un UITextRange .

Voici en gros ce que je recherche :

- (CGRect)frameOfTextRange:(NSRange)range inTextView:(UITextView *)textView {

    UITextRange*range2 = [UITextRange rangeWithNSRange:range]; //DOES NOT EXIST 
    CGRect rect = [textView firstRectForRange:range2];
    return rect;
}

Apple dit qu'il faut sous-classer UITextRange y UITextPosition afin d'adopter le UITextInput protocole. Je ne fais pas cela, mais j'ai quand même essayé, en suivant le code d'exemple de la doc et en passant la sous-classe à firstRectForRange ce qui a entraîné un crash.

S'il existe un moyen plus simple d'ajouter des couleurs différentes UILables à une vue de texte, s'il vous plaît dites-moi. J'ai essayé d'utiliser UIWebView avec content editable mis à TRUE, mais je n'aime pas communiquer avec JS, et la coloration est la seule chose dont j'ai besoin.

Merci d'avance.

100voto

Nicolas Bachschmidt Points 4441

Vous pouvez créer une plage de texte avec la méthode textRangeFromPosition:toPosition . Cette méthode nécessite deux positions, vous devez donc calculer les positions pour le début et la fin de votre plage. Cela se fait avec la méthode positionFromPosition:offset qui renvoie une position à partir d'une autre position et un décalage de caractère.

- (CGRect)frameOfTextRange:(NSRange)range inTextView:(UITextView *)textView
{
    UITextPosition *beginning = textView.beginningOfDocument;
    UITextPosition *start = [textView positionFromPosition:beginning offset:range.location];
    UITextPosition *end = [textView positionFromPosition:start offset:range.length];
    UITextRange *textRange = [textView textRangeFromPosition:start toPosition:end];
    CGRect rect = [textView firstRectForRange:textRange];
    return [textView convertRect:rect fromView:textView.textInputView];
}

17voto

auco Points 2663

C'est un peu ridicule que cela semble si compliqué. Un simple "contournement" serait de sélectionner la plage (accepte NSRange) et ensuite de lire la selectedTextRange (renvoie UITextRange) :

- (CGRect)frameOfTextRange:(NSRange)range inTextView:(UITextView *)textView {
    textView.selectedRange = range;
    UITextRange *textRange = [textView selectedTextRange]; 
    CGRect rect = [textView firstRectForRange:textRange];
    return rect;
}

Cela a fonctionné pour moi même si le textView n'est pas le premier répondant.


Si vous ne voulez pas que la sélection persiste, vous pouvez soit réinitialiser la selectedRange :

textView.selectedRange = NSMakeRange(0, 0);

...ou sauvegarder la sélection actuelle et la restaurer ensuite

NSRange oldRange = textView.selectedRange;
// do something
// then check if the range is still valid and
textView.selectedRange = oldRange;

11voto

CodenameDuchess Points 806

Swift 4 de la réponse d'Andrew Schreiber pour un copier/coller facile

extension NSRange {
    func toTextRange(textInput:UITextInput) -> UITextRange? {
        if let rangeStart = textInput.position(from: textInput.beginningOfDocument, offset: location),
            let rangeEnd = textInput.position(from: rangeStart, offset: length) {
            return textInput.textRange(from: rangeStart, to: rangeEnd)
        }
        return nil
    }
}

6voto

Pour répondre à la question du titre, voici une Extension de Swift 2 qui crée une UITextRange à partir d'une NSRange.

Le seul initialisateur pour UITextRange est une méthode d'instance sur le protocole UITextInput, donc l'extension exige également que vous passiez dans UITextInput tel que UITextField o UITextView .

extension NSRange {
    func toTextRange(textInput textInput:UITextInput) -> UITextRange? {
        if let rangeStart = textInput.positionFromPosition(textInput.beginningOfDocument, offset: location),
            rangeEnd = textInput.positionFromPosition(rangeStart, offset: length) {
            return textInput.textRangeFromPosition(rangeStart, toPosition: rangeEnd)
        }
        return nil
    }
}

1voto

user2237877 Points 11

Cela ne fonctionne que si votre textView a son sélectionnable l'état est réglé sur OUI ! Dans le cas contraire, les méthodes du protocole UITextInput renvoient des données incorrectes, par exemple beginOfDocument renverra nil.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X