web-dev-qa-db-fra.com

Comment trouver le nombre réel de lignes de UILabel?

Comment puis-je trouver le nombre réel nombre de lignes d'une UILabel après l'avoir initialisée avec une text et une font? J'ai défini sa propriété numberOfLines sur 0, de sorte qu'il sera étendu au nombre de lignes nécessaires. Mais alors, comment puis-je savoir combien de lignes il a finalement obtenues après avoir défini sa text

J'ai trouvé des questions similaires, mais aucune ne semble fournir une réponse concise et il me semble qu'il doit être très facile de l'obtenir sans aucun frais supplémentaire pour jongler avec les boundingRectWithSize ou sizeWithFont, ...

52
nburk

Tout d'abord définir le texte dans UILabel

Première option:  

Tout d'abord, calculez la hauteur du texte en fonction de la police:

NSInteger lineCount = 0;
CGSize labelSize = (CGSize){yourLabel.frame.size.width, MAXFLOAT};
CGRect requiredSize = [self boundingRectWithSize:labelSize  options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName: yourLabel.font} context:nil];

Maintenant, calcule le nombre de lignes:

int charSize = lroundf(yourLabel.font.lineHeight);
int rHeight = lroundf(requiredSize.height);
lineCount = rHeight/charSize;
NSLog(@"No of lines: %i",lineCount);

Deuxième option :

 NSInteger lineCount = 0;
 CGSize textSize = CGSizeMake(yourLabel.frame.size.width, MAXFLOAT);
 int rHeight = lroundf([yourLabel sizeThatFits:textSize].height);
 int charSize = lroundf(yourLabel.font.lineHeight);
 lineCount = rHeight/charSize;
 NSLog(@"No of lines: %i",lineCount);
44
Paresh Navadiya

Aucun de ceux-ci n'a fonctionné pour moi. Ci-dessous on fait,

Swift 4.2:

extension UILabel {
    func calculateMaxLines() -> Int {
        let maxSize = CGSize(width: frame.size.width, height: CGFloat(Float.infinity))
        let charSize = font.lineHeight
        let text = (self.text ?? "") as NSString
        let textSize = text.boundingRect(with: maxSize, options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: font], context: nil)
        let linesRoundedUp = Int(ceil(textSize.height/charSize)) 
        return linesRoundedUp
    }    
}

Swift 4/4.1:

extension UILabel {

    func calculateMaxLines() -> Int {
        let maxSize = CGSize(width: frame.size.width, height: CGFloat(Float.infinity))
        let charSize = font.lineHeight
        let text = (self.text ?? "") as NSString
        let textSize = text.boundingRect(with: maxSize, options: .usesLineFragmentOrigin, attributes: [.font: font], context: nil)
        let linesRoundedUp = Int(ceil(textSize.height/charSize)) 
        return linesRoundedUp
    }

}

Swift 3:

extension UILabel {

    func calculateMaxLines() -> Int {
        let maxSize = CGSize(width: frame.size.width, height: CGFloat(Float.infinity))
        let charSize = font.lineHeight
        let text = (self.text ?? "") as NSString
        let textSize = text.boundingRect(with: maxSize, options: .usesLineFragmentOrigin, attributes: [NSFontAttributeName: font], context: nil)
        let linesRoundedUp = Int(ceil(textSize.height/charSize)) 
        return linesRoundedUp
    }

}
41
Kurt J

Swift 3 (IOS 10.3)

extension UILabel {
    var numberOfVisibleLines: Int {
        let textSize = CGSize(width: CGFloat(self.frame.size.width), height: CGFloat(MAXFLOAT))
        let rHeight: Int = lroundf(Float(self.sizeThatFits(textSize).height))
        let charSize: Int = lroundf(Float(self.font.pointSize))
        return rHeight / charSize
    }
}

Utilisation

print(yourLabel.numberOfVisibleLines)
34
ramchandra n

Voici une version de Swift de la solution @Paresh:

func lines(label: UILabel) -> Int {
    let textSize = CGSize(width: label.frame.size.width, height: CGFloat(Float.infinity))
    let rHeight = lroundf(Float(label.sizeThatFits(textSize).height))
    let charSize = lroundf(Float(label.font.lineHeight))
    let lineCount = rHeight/charSize
    return lineCount
}

EDIT: Je ne sais pas pourquoi, mais le code renvoie 2 lignes de plus que le nombre réel de lignes. Pour ma solution, je les ai juste soustraites avant de retourner lineCount.

15
danywarner

Les autres réponses ici ne respectent pas la propriété numberOfLines de UILabel lorsqu'elle est définie sur autre chose que 0.

Voici une autre option que vous pouvez ajouter à votre catégorie ou sous-classe:

- (NSUInteger)lineCount
{
    CGSize size = [self sizeThatFits:CGSizeMake(self.frame.size.width, CGFLOAT_MAX)];
    return MAX((int)(size.height / self.font.lineHeight), 0);
}

Quelques notes:

  • J'utilise ceci sur un UILabel avec un texte attribué, sans jamais définir réellement la propriété font, et cela fonctionne bien. Évidemment, vous auriez des problèmes si vous utilisiez plusieurs polices dans votre attributedText.
  • Si vous sous-classez UILabel pour avoir des incrustations Edge personnalisées (par exemple, en remplaçant drawTextInRect:, ce qui est une astuce intéressante que j'ai trouvée ici ), vous devez vous rappeler de prendre en compte ces incrustes lors du calcul de size ci-dessus. Par exemple: CGSizeMake(self.frame.size.width - (self.insets.left + self.insets.right), CGFLOAT_MAX)
10
pejalo

Voici le code Swift3 Ici vous pouvez définir la valeur Int et obtenir la hauteur de la taille du texte en utilisant (MAXFLOAT) et en utilisant cette hauteur, vous pouvez obtenir la hauteur totale de UILabel et en la divisant par caractère taille, vous pouvez obtenir le nombre de lignes réel d’UILabel.

var lineCount: Int = 0
var textSize = CGSize(width: CGFloat(yourLabel.frame.size.width), height: CGFloat(MAXFLOAT))
var rHeight: Int = lroundf(yourLabel.sizeThatFits(textSize).height)
var charSize: Int = lroundf(yourLabel.font.leading)
lineCount = rHeight / charSize
print("No of lines: \(lineCount)")
8

Pour faire suite à la réponse de @ Prince, j’ai maintenant implémenté un category on UILabel comme suit (notez que j’ai corrigé quelques erreurs de syntaxe mineures dans sa réponse qui ne laissaient pas le code compiler):

UILabel + Util.h

#import <UIKit/UIKit.h>

@interface UILabel (Util)
- (NSInteger)lineCount;
@end

UILabel + Util.,

#import "UILabel+Util.h"

@implementation UILabel (Util)

- (NSInteger)lineCount
{
    // Calculate height text according to font
    NSInteger lineCount = 0;
    CGSize labelSize = (CGSize){self.frame.size.width, FLT_MAX};
    CGRect requiredSize = [self.text boundingRectWithSize:labelSize  options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName: self.font} context:nil];

    // Calculate number of lines
    int charSize = self.font.leading;
    int rHeight = requiredSize.size.height;
    lineCount = rHeight/charSize;

    return lineCount;
}

@end
4
nburk

Vous pouvez trouver le nombre total de lignes disponibles dans votre étiquette personnalisée Veuillez vérifier ce code ...

NSInteger numberOfLines = [self lineCountForText:@"YOUR TEXT"];

- (int)lineCountForText:(NSString *) text
{
    UIFont *font = [UIFont systemFontOfSize: 15.0];
    int width=Your_LabelWidht;

    CGRect rect = [text boundingRectWithSize:CGSizeMake(width, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin  attributes:@{NSFontAttributeName : font} context:nil];
    return ceil(rect.size.height / font.lineHeight);
}
4
Kaushik Movaliya

Il semble que le site Web officiel du développeur mentionne une solution Comptage de lignes de texte dans Objc. Toutefois, cela suppose que vous ayez une référence à une vue de texte configurée avec un gestionnaire de disposition, un stockage de texte et un conteneur de texte. Malheureusement, UILabel ne nous les expose pas, nous devons donc les créer avec la même configuration que UILabel.

J'ai traduit le code Objc en Swift comme suit. Cela semble bien fonctionner pour moi.

extension UILabel {
    var actualNumberOfLines: Int {
        let textStorage = NSTextStorage(attributedString: self.attributedText!)
        let layoutManager = NSLayoutManager()
        textStorage.addLayoutManager(layoutManager)
        let textContainer = NSTextContainer(size: self.bounds.size)
        textContainer.lineFragmentPadding = 0
        textContainer.lineBreakMode = self.lineBreakMode
        layoutManager.addTextContainer(textContainer)

        let numberOfGlyphs = layoutManager.numberOfGlyphs
        var numberOfLines = 0, index = 0, lineRange = NSMakeRange(0, 1)

        while index < numberOfGlyphs {
            layoutManager.lineFragmentRect(forGlyphAt: index, effectiveRange: &lineRange)
            index = NSMaxRange(lineRange)
            numberOfLines += 1
        }
        return numberOfLines
    }
}
1
sam
let l = UILabel()
l.numberOfLines = 0
l.layer.frame.size.width = self.view.frame.width - 40 /*padding(20 + 20)*/

l.font = UIFont(name: "BwModelica-Bold", size: 16.0)

l.text = "Random Any length Text!!"

let noOfLines = ceil(l.intrinsicContentSize.width) / l.frame.width)

let lbl_height = noOfLines * l.intrinsicContentSize.height

Ce sera votre hauteur dynamique exacte de Label et le nombre de lignes. Bonne codage !!!

0
onkar dhanlobhe

Xamarin.iOS

Merci aux réponses fournies par tous ci-dessus.

Cela donne le nombre de lignes visibles.

public static int VisibleLineCount(this UILabel label)
{
    var textSize = new CGSize(label.Frame.Size.Width, nfloat.MaxValue);
    nfloat rHeight = label.SizeThatFits(textSize).Height;
    nfloat charSize = label.Font.LineHeight;
    return Convert.ToInt32(rHeight / charSize);
}

Cela donne le nombre réel de lignes que le texte occupera à l'écran.

public static int LineCount(this UILabel label)
{
    var maxSize = new CGSize(label.Frame.Size.Width, nfloat.MaxValue);
    var charSize = label.Font.LineHeight;
    var text = (label.Text ?? "").ToNSString();
    var textSize = text.GetBoundingRect(maxSize, NSStringDrawingOptions.UsesLineFragmentOrigin, new UIStringAttributes() { Font = label.Font }, null);
    return Convert.ToInt32(textSize.Height / charSize);
}

Une méthode d'assistance que je trouve utile pour mon cas d'utilisation. 

public static bool IsTextTruncated(this UILabel label)
{
    if (label.Lines == 0)
    {
        return false;
    }
    return (label.LineCount() > label.Lines);
 }

Pour obtenir un nombre de lignes plus précis:

  • Utilisez font.lineHeight au lieu de font.pointSize
  • round () le nombre de lignes après division
0
Baron Ch'ng

Notez que la réponse de @ kurt-j ne fonctionnera pas toujours. Dans certains cas, vous devrez fournir manuellement la largeur de l'étiquette. Étant donné que ces cas existent, il est judicieux d’avoir un paramètre optionnel width, même si vous ne l’utilisez pas.

Swift 4.2:

extension UILabel {
    func calculateMaxLines(actualWidth: CGFloat?) -> Int {
        var width = frame.size.width
        if let actualWidth = actualWidth {
            width = actualWidth
        }
        let maxSize = CGSize(width: width, height: CGFloat(Float.infinity))
        let charSize = font.lineHeight
        let text = (self.text ?? "") as NSString
        let textSize = text.boundingRect(with: maxSize, options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: font], context: nil)
        let linesRoundedUp = Int(ceil(textSize.height/charSize)) 
        return linesRoundedUp
    }    
}
0
pyromancer2