Obliczanie Rozmiaru Tekstu UILabel

Rysuję UILabels programowo. Dostają swoje rozmiary z bazy danych. Więc nie mogę po prostu użyć sizeToFit. Zaimplementowałem już funkcję, która przerysowuje UILabels z przelicznikiem. Więc wszystko, co muszę znaleźć, to tekst w UILabel z mojego punktu widzenia, który wymagałby maksymalnego stosunku do przerysowania UILabels. Więc w końcu muszę zrobić coś takiego:

    double ratio = 1.00;
    for (UILabel* labels in sec.subviews) {

        float widthLabel = labels.frame.size.width;
        float heightLabel = labels.frame.size.height;
        float heightText = //get the text height here
        float widthText = //get the text width here
        if (widthLabel < widthText) {
            ratio = MAX(widthText/widthLabel,ratio);
        }
        if (heightLabel < heightText) {
            ratio = MAX(heightText/heightLabel, ratio);
        }
    }
    //redraw UILabels with the given ratio here

Więc jak Mogę uzyskać rozmiar wysokości i szerokości tekstu, ponieważ część mojego tekstu nie pasuje do etykiety, której nie mogę po prostu użyć granice etykiet? Używam Xcode 5 i iOS 7.

Author: Sarp Kaya, 2013-10-02

10 answers

Wszystkie metody

Są przestarzałe w iOS 7. Użyj tego zamiast tego.

CGRect labelRect = [text
                    boundingRectWithSize:labelSize
                    options:NSStringDrawingUsesLineFragmentOrigin
                    attributes:@{
                     NSFontAttributeName : [UIFont systemFontOfSize:14]
                    }
                    context:nil];

Zobacz też https://developer.apple.com/documentation/foundation/nsstring/1619914-sizewithfont .

UPDATE-przykład boundingRectWithSize output

Za twój komentarz zrobiłem prosty test. Kod i wyjście znajduje się poniżej.

// code to generate a bounding rect for text at various font sizes
NSString *text = @"This is a long sentence. Wonder how much space is needed?";
for (NSNumber *n in @[@(12.0f), @(14.0f), @(18.0f)]) {
    CGFloat fontSize = [n floatValue];
    CGRect r = [text boundingRectWithSize:CGSizeMake(200, 0)
                                  options:NSStringDrawingUsesLineFragmentOrigin
                               attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:fontSize]}
                                  context:nil];
    NSLog(@"fontSize = %f\tbounds = (%f x %f)",
          fontSize,
          r.size.width,
          r.size.height);
}

Daje to następujące wyjście (należy pamiętać, że granice zmieniają się zgodnie z oczekiwaniami, gdy rozmiar czcionki staje się większy):

fontSize = 12.000000    bounds = (181.152008 x 28.632000)
fontSize = 14.000000    bounds = (182.251999 x 50.105999)
fontSize = 18.000000    bounds = (194.039993 x 64.421997)
 68
Author: XJones,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-20 09:12:55

Length pobiera liczbę znaków. Jeśli chcesz uzyskać szerokość tekstu:

Objective-C

CGSize textSize = [label.text sizeWithAttributes:@{NSFontAttributeName:[label font]}];

Swift 4

let size = label.text?.size(withAttributes: [.font: label.font]) ?? .zero
To daje Ci Rozmiar. I możesz porównać textSize.width każdej etykiety.
 51
Author: H. Serdar Çınar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-19 01:41:43

Kolejny prosty sposób na to, o którym jeszcze nie wspomniałem:

CGSize textSize = [label intrinsicContentSize];

(to działa poprawnie tylko po ustawieniu tekstu i czcionki etykiety, oczywiście.)

 28
Author: poff,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-14 21:52:51

Oto wariant swift.

let font = UIFont(name: "HelveticaNeue", size: 25)!
let text = "This is some really long text just to test how it works for calculating heights in swift of string sizes. What if I add a couple lines of text?"

let textString = text as NSString

let textAttributes = [NSFontAttributeName: font]

textString.boundingRectWithSize(CGSizeMake(320, 2000), options: .UsesLineFragmentOrigin, attributes: textAttributes, context: nil)
 17
Author: Collin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-29 14:19:22

Mała rada chłopaki, jeśli tak jak ja używacie, boundingRectWithSize z [UIFont systemFontOFSize:14]

Jeśli twój łańcuch ma długość dwóch linii, zwracana wysokość rect wynosi około 33,4 punktu.

Nie popełniaj błędu, tak jak ja, rzucając go w int, ponieważ 33,4 staje się 33, a etykieta wysokości 33 punktów przechodzi z dwóch do jednej linii!

 3
Author: Martin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-12 15:42:56

Problem z

CGRect r = [text boundingRectWithSize:CGSizeMake(200, 0)
                              options:NSStringDrawingUsesLineFragmentOrigin
                           attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:fontSize]}
                              context:nil];

Jest boundingRectWithSize, która określa maksymalną wartość, jaką może mieć CGRect.

Moim rozwiązaniem tego problemu jest sprawdzenie, czy przekracza, jeśli nie, to tekst może zmieścić się w etykiecie. Zrobiłem to za pomocą pętli.

NSString *text = @"This is a long sentence. Wonder how much space is needed?";
CGFloat width = 100;
CGFloat height = 100;
bool sizeFound = false;
while (!sizeFound) {
    NSLog(@"Begin loop");
    CGFloat fontSize = 14;
    CGFloat previousSize = 0.0;
    CGFloat currSize = 0.0;
    for (float fSize = fontSize; fSize < fontSize+6; fSize++) {
        CGRect r = [text boundingRectWithSize:CGSizeMake(width, height)
                                      options:NSStringDrawingUsesLineFragmentOrigin
                                   attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:fSize]}
                                      context:nil];
        currSize =r.size.width*r.size.height;
        if (previousSize >= currSize) {
            width = width*11/10;
            height = height*11/10;
            fSize = fontSize+10;
        }
        else {
            previousSize = currSize;
        }
        NSLog(@"fontSize = %f\tbounds = (%f x %f) = %f",
              fSize,
              r.size.width,
              r.size.height,r.size.width*r.size.height);
    }
    if (previousSize == currSize) {
        sizeFound = true;
    }

}
NSLog(@"Size found with width %f and height %f", width, height);

Po każdej iteracji wielkość wysokości i szerokości zwiększa się o 10% jej wartości.

Powodem, dla którego wybrałem 6, jest to, że nie chciałem, aby etykieta była zbyt miękka.

Dla rozwiązania, które nie używa pętle:

NSString *text = @"This is a long sentence. Wonder how much space is needed?";
CGFloat width = 100;
CGFloat height = 100;

CGFloat currentFontSize = 12;
CGRect r1 = [text boundingRectWithSize:CGSizeMake(width, height)
                              options:NSStringDrawingUsesLineFragmentOrigin
                           attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:currentFontSize+6]}
                              context:nil];

CGRect r2 = [text boundingRectWithSize:CGSizeMake(width, height)
                               options:NSStringDrawingUsesFontLeading
                            attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:currentFontSize+6]}
                               context:nil];

CGFloat firstVal =r1.size.width*r1.size.height;
CGFloat secondVal =r2.size.width*r2.size.height;

NSLog(@"First val %f and second val is %f", firstVal, secondVal);

if (secondVal > firstVal) {
    float initRat = secondVal/firstVal;

    float ratioToBeMult = sqrtf(initRat);

    width *= ratioToBeMult;
    height *= ratioToBeMult;
}

NSLog(@"Final width %f and height %f", width, height);

//for verifying
for (NSNumber *n in @[@(12.0f), @(14.0f), @(17.0f)]) {
    CGFloat fontSize = [n floatValue];
    CGRect r = [text boundingRectWithSize:CGSizeMake(width, height)
                                  options:NSStringDrawingUsesLineFragmentOrigin
                               attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:fontSize]}
                                  context:nil];
    NSLog(@"fontSize = %f\tbounds = (%f x %f) = %f",
          fontSize,
          r.size.width,
          r.size.height,r.size.width*r.size.height);
    firstVal =r.size.width*r.size.height;
}

Gdzie ostatnia pętla jest dowodem, że większa czcionka może dać większy rozmiar.

 2
Author: Sarp Kaya,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-04 03:33:16

Za pomocą tej linii kodu możemy uzyskać rozmiar tekstu na etykiecie.

let str = "Sample text"
let size = str.sizeWithAttributes([NSFontAttributeName:UIFont.systemFontOfSize(17.0)])

Możemy więc użyć zarówno szerokości, jak i wysokości.

 1
Author: Ramakrishna,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-04 05:43:55

Rozwiązanie, które współpracuje z etykietami wielowierszowymi (Swift 4), Aby obliczyć wysokość ze stałej szerokości:

let label = UILabel(frame: .zero)
label.numberOfLines = 0 // multiline
label.font = UIFont.systemFont(ofSize: UIFont.labelFontSize) // your font
label.preferredMaxLayoutWidth = width // max width
label.text = "This is a sample text.\nWith a second line!" // the text to display in the label

let height = label.intrinsicContentSize.height
 1
Author: chrisben,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-11-20 15:40:27

Msgstr string get size:

let msgStr:NSString = Data["msg"]! as NSString
let messageSize = msgStr.boundingRect(with: CGSize(width: ChatTable.frame.width-116, height: CGFloat.infinity), options: .usesLineFragmentOrigin, attributes: [NSFontAttributeName:UIFont(name: "Montserrat-Light", size: 14)!], context: nil).size
 0
Author: Jayesh Miruliya,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-10 05:58:05

Swift 3.0

func getLabelHeight() -> CGFloat {
    let font = UIFont(name: "OpenSans", size: 15)!
    let textString = "Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." as NSString

    let textAttributes = [NSFontAttributeName: font]

    let rect = textString.boundingRect(with: CGSize(width: 320, height: 2000), options: .usesLineFragmentOrigin, attributes: textAttributes, context: nil)
    return rect.size.height
}
 0
Author: Abhishek Jain,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-18 08:55:17