web-dev-qa-db-fra.com

Compter le nombre de lignes dans une UITextView, lignes encapsulées par taille d'image

Je voulais savoir quand un texte est entouré par le cadre de la vue, y a-t-il un séparateur avec lequel nous pouvons identifier si le texte est entouré ou non?.

Par exemple, si ma vue texte a une largeur de 50 px et que le texte dépasse cette limite, le texte est renvoyé à la ligne suivante.

Je voulais compter le nombre de lignes dans ma vue de texte. Maintenant "\ n" et "\ r" ne m'aident pas.

Mon code est:

NSCharacterSet *aCharacterSet = [NSCharacterSet characterSetWithCharactersInString:@"\n\r"];
    NSArray *myArray = [textViewText componentsSeparatedByCharactersInSet:aCharacterSet];
    NSLog(@"%d",[myArray count]);
22
Abhinav

Cette variation tient compte de la manière dont vous enroulez vos lignes et de la taille maximale de UITextView, et peut générer une hauteur plus précise. Par exemple, si le texte ne correspond pas, il sera tronqué à la taille visible et si vous placez des mots entiers (ce qui est la valeur par défaut), cela peut entraîner plus de lignes que si vous agissiez autrement.

UIFont *font = [UIFont boldSystemFontOfSize:11.0];
CGSize size = [string sizeWithFont:font 
                      constrainedToSize:myUITextView.frame.size 
                      lineBreakMode:UILineBreakModeWordWrap]; // default mode
float numberOfLines = size.height / font.lineHeight;
27
Jano

Vous devez utiliser la propriété lineHeight et la police lineHeight:

Objectif c

int numLines = txtview.contentSize.height / txtview.font.lineHeight;

Rapide

let numLines = (txtview.contentSize.height / txtview.font.lineHeight) as? Int

Je reçois le nombre correct de lignes, j'espère que cela vous aidera également.

18
Himanshu padia

Swift 3:

let layoutManager:NSLayoutManager = textView.layoutManager
let numberOfGlyphs = layoutManager.numberOfGlyphs
var numberOfLines = 0
var index = 0
var lineRange:NSRange = NSRange()

while (index < numberOfGlyphs) {
    layoutManager.lineFragmentRect(forGlyphAt: index, effectiveRange: &lineRange)
    index = NSMaxRange(lineRange);
    numberOfLines = numberOfLines + 1
}

print(numberOfLines)
13
castillejoale

J'ai trouvé la solution idéale à ce problème dans/ Guide de programmation de mise en page de texte . Voici la solution fournie par Apple:

NSLayoutManager *layoutManager = [textView layoutManager];
unsigned numberOfLines, index;
unsigned numberOfGlyphs = [layoutManager numberOfGlyphs];
NSRange lineRange;

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

Cela pourrait facilement être écrit dans une extension pour UITextView ou sous forme de méthode autonome prenant un objet UITextView comme paramètre.

9
Luke Chase

Extension rapide:

Utilisation de @himanshu padia answer

//MARK: - UITextView
extension UITextView{

    func numberOfLines() -> Int{
        if let fontUnwrapped = self.font{
            return Int(self.contentSize.height / fontUnwrapped.lineHeight)
        }
        return 0
    }

}

Usage: yourTextView.numberOfLines()

sachez que si pour une raison quelconque la police de la vue texte est nulle, le retour sera zéro.

8
Juan Boero

Vous devez tenir compte de textView.textContainerInset, mais aussi arrondir la valeur calculée, car le numéro de ligne est un entier.

float rawLineNumber = (textView.contentSize.height - textView.textContainerInset.top - textView.textContainerInset.bottom) / textView.font.lineHeight;
int finalLineNumber = round(rawLineNumber)

En cas réel, vous pouvez voir le résultat suivant RawLineNumber = 3.008099 FinalLineNumber = 3 (3 lignes)

7
Jacky
   func numberOfLines(textView: UITextView) -> Int {
    let layoutManager = textView.layoutManager
    let numberOfGlyphs = layoutManager.numberOfGlyphs
    var lineRange: NSRange = NSMakeRange(0, 1)
    var index = 0
    var numberOfLines = 0

    while index < numberOfGlyphs {
        layoutManager.lineFragmentRect(forGlyphAt: index, effectiveRange: &lineRange)
        index = NSMaxRange(lineRange)
        numberOfLines += 1
    }
    return numberOfLines
}

Travailler bien pour moi

4
Softlabsindia

Utilisez ceci (où _text_v est votre vue texte):

-(NSInteger) linesCount {
    return _text_v.contentSize.height/_text_v.font.lineHeight;
}
4
Max

Swift 4 version de Luke Chase réponse

let numberOfGlyphs = textView.layoutManager.numberOfGlyphs
var index = 0, numberOfLines = 0
var lineRange = NSRange(location: NSNotFound, length: 0)

while index < numberOfGlyphs {
  textView.layoutManager.lineFragmentRect(forGlyphAt: index, effectiveRange: &lineRange)
  index = NSMaxRange(lineRange)
  numberOfLines += 1
}
1
Yeesha

J'ai passé beaucoup de temps à essayer de calculer en temps réel le nombre de lignes pour une entrée TextView (disons une zone de texte de chat) et la seule solution qui fonctionne dans ce cas est celle de Luke Chase (pour une raison ou une autre, l'approche frame.height semble ne mettre à jour que les 3e ou 4e lettres saisies dans un textView et n’est donc pas précis). 

Comme un commentateur l'a mentionné, il existe un petit bogue dans lequel les sauts de ligne générés par l'utilisateur ("\ n" ou sur la touche de retour au clavier) ne sont pas correctement comptabilisés. Encore plus étrange, il ne fait que "rater" la première coupure de ligne, toutes les suivantes sont correctement capturées (disons que vous allez à la ligne 4 fois, elle ne renverra que 3 lignes manquant clairement la première coupure de ligne).

Donc, pour contourner ce bogue, je regarde simplement enregistrer le premier saut de ligne (caractère "\ n") et ajouter manuellement une ligne au nombre de lignes renvoyées par la méthode gliph.

Dans le code qui donne: 

    func offSetTableViewIfNeeded() {
    let numberOfGlyphs = textView.layoutManager.numberOfGlyphs
    var index : Int = 0
    var lineRange = NSRange(location: NSNotFound, length: 0)
    var currentNumOfLines : Int = 0
    var numberOfParagraphJump : Int = 0

    while index < numberOfGlyphs {
        textView.layoutManager.lineFragmentRect(forGlyphAt: index, effectiveRange: &lineRange)
        index = NSMaxRange(lineRange)
        currentNumOfLines += 1

        // Observing whether user went to line and if it's the first such line break, accounting for it.
        if textView.text.last == "\n", numberOfParagraphJump == 0 {
            numberOfParagraphJump = 1
        }
    }

    currentNumOfLines += numberOfParagraphJump

    print("Number of lines is:", currentNumOfLines)

J'espère que cela aidera d'autres personnes aux prises avec le comportement extrêmement étrange de l'entrée textView (vous ne pouvez pas comprendre pourquoi Apple ne fournit pas de méthode # de ligne prête à l'emploi!). 

0
Franc