Как найти фактическое количество строк UILabel?

Как я могу найти фактическое количество строк UILabel после того, как я инициализировал его с помощью text и a font? Я установил для этого свойства numberOfLines значение 0, поэтому он будет расширяться до тех пор, пока не потребуется много строк. Но потом, как я могу узнать, сколько строк оно получило после того, как я установил его text?

Я нашел похожие вопросы, но ни один из них не дает краткого ответа, и мне кажется, что его действительно легко получить без каких-либо накладных расходов при жонглировании с помощью boundingRectWithSize или sizeWithFont,...

Ответ 1

Сначала установите текст в UILabel

Первый вариант:

Сначала вычислите высоту текста в соответствии с шрифтом:

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

Теперь вычислите количество строк:

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

Второй вариант:

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

Ответ 2

Ничто из этого не помогло мне. Ниже один сделал,

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
    }

}

Свифт 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
    }

}

Ответ 3

Свифт 5 (IOS 12.2)

Получите максимальное количество строк, необходимое для метки, чтобы отобразить текст без усечения.

extension UILabel {
    var maxNumberOfLines: Int {
        let maxSize = CGSize(width: frame.size.width, height: CGFloat(MAXFLOAT))
        let text = (self.text ?? "") as NSString
        let textHeight = text.boundingRect(with: maxSize, options: .usesLineFragmentOrigin, attributes: [.font: font], context: nil).height
        let lineHeight = font.lineHeight
        return Int(ceil(textHeight / lineHeight))
    }
}

Получить максимальное количество строк можно отобразить в метке с ограниченными границами. Используйте это свойство после назначения текста метке.

extension UILabel {
    var numberOfVisibleLines: Int {
        let maxSize = CGSize(width: frame.size.width, height: CGFloat(MAXFLOAT))
        let textHeight = sizeThatFits(maxSize).height
        let lineHeight = font.lineHeight
        return Int(ceil(textHeight / lineHeight))
    }
}

использование

print(yourLabel.maxNumberOfLines)
print(yourLabel.numberOfVisibleLines)

Ответ 4

Вот оперативная версия решения @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: я не знаю, почему, но код возвращает еще 2 строки, чем фактическое количество строк, для моего решения я просто вычитал их перед возвратом lineCount.

Ответ 5

Другие ответы здесь не соответствуют свойству numberOfLines UILabel, когда оно установлено на что-то отличное от 0.

Вот еще один вариант, который вы можете добавить в свою категорию или подкласс:

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

Некоторые примечания:

  • Я использую это в UILabel с приписанным текстом, даже не устанавливая свойство font, и он работает нормально. Очевидно, что вы столкнулись с проблемами, если бы вы использовали несколько шрифтов в attributedText.
  • Если вы выполняете подклассификацию UILabel, чтобы иметь пользовательские вставки края (например, переопределяя drawTextInRect:, что является опрятным трюком, я нашел здесь), тогда вы не должны учитывать эти вставки при расчете size выше. Например: CGSizeMake(self.frame.size.width - (self.insets.left + self.insets.right), CGFLOAT_MAX)

Ответ 6

Вот код Swift3 здесь вы можете определить значение Int и получить высоту размера текста, используя (MAXFLOAT), и используя эту высоту, вы можете получить общую высоту UILabel, и, выделив эту общую высоту по размеру символа, вы можете получить фактическое количество строк 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)")

Ответ 7

В ответ на @Prince я теперь применил категорию на UILabel следующим образом (обратите внимание, что я исправил некоторые незначительные ошибки синтаксиса в его ответе, которые не позволяли компилировать код):

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

Ответ 8

Вы можете найти общее количество строк, доступных на вашей пользовательской метке Проверьте этот код...

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

Ответ 9

Похоже, что официальный сайт разработчика упоминает одно решение Подсчет строк текста в Objc. Однако предполагается, что у вас есть ссылка на текстовое представление, настроенное с помощью менеджера макета, текстового хранилища и текстового контейнера. К сожалению, UILabel не предоставляет их нам, поэтому нам нужно создать их с той же конфигурацией, что и UILabel.

Я перевёл код Objc в swift следующим образом. Мне кажется, это хорошо работает.

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

Ответ 10

Xamarin.iOS

Спасибо всем за ответы, предоставленные выше.

Это получает количество видимых линий.

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

Получается фактическое количество строк, которые текст будет занимать на экране.

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

Вспомогательный метод, который я считаю полезным для моего варианта использования.

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

Чтобы получить более точное количество строк:

  • Используйте font.lineHeight вместо font.pointSize
  • round() количество строк после деления

Ответ 11

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

Это будет ваша точная динамическая высота метки и количество строк. Удачного кодирования !!!

Ответ 12

Обратите внимание, что @kurt-j ответ не всегда будет работать. В некоторых случаях вам придется вручную указывать ширину метки. Поскольку такие случаи существуют, рекомендуется иметь необязательный параметр width, даже если вы не используете его в конечном итоге.

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

Ответ 13

Xamarin iOS

label.Text = text;

var lineCount = 0;
var textSize = new CGSize(label.Frame.Size.Width, float.MaxValue);
var height = label.SizeThatFits(textSize).Height;
var fontHeight = label.Font.LineHeight;

lineCount = Convert.ToInt32(height / fontHeight);