sizeWithFont jest przestarzała. boundingRectWithSize zwraca nieoczekiwaną wartość

82

W iOS7 sizeWithFontjest przestarzała, więc używam boundingRectWithSize(która zwraca wartość CGRect). Mój kod:

 UIFont *fontText = [UIFont fontWithName:[AppHandlers zHandler].fontName size:16];
                    // you can use your font.

 CGSize maximumLabelSize = CGSizeMake(310, 9999);

 CGRect textRect = [myString boundingRectWithSize:maximumLabelSize   
                             options:NSStringDrawingUsesLineFragmentOrigin
                             attributes:@{NSFontAttributeName:fontText}
                             context:nil];

 expectedLabelSize = CGSizeMake(textRect.size.width, textRect.size.height);

W programie textRectotrzymuję rozmiar większy niż mój maximumLabelSize, inny rozmiar niż podczas używania sizeWithFont. Jak mogę rozwiązać ten problem?

Nirav Jain
źródło
Otrzymuję ten problem ze wszystkimi czcionkami, nie tylko czcionką systemową lub Helvetica.
Nirav Jain
czy masz jakiś pomysł, jak to zrobić?
Nirav Jain
Pomocny może być konkretny przykład nazwy czcionki, tekstu i niezgodnych rozmiarów.
Eiko
Kiedyś używałem CTFramesetterSuggestFrameSizeWithConstraints w iOS6 do obliczania wysokości atrybutu atrybutu, który zawsze zwraca prawidłową wysokość. W iOS7 zarówno CTFramesetterSuggestFrameSizeWithConstraints, jak i boundingRectWithSize dają mi zły wynik wysokości. Założę się, że to błąd wprowadzony w iOS7 i wydaje się, że nie ma jeszcze rozwiązania.
Arnold Tang
Mam również ten sam problem, lepiej jest użyć tttattributedlabel
Sri ..

Odpowiedzi:

151

Co powiesz na stworzenie nowej etykiety i użycie sizeThatFit:(CGSize)size?

UILabel *gettingSizeLabel = [[UILabel alloc] init];
gettingSizeLabel.font = [UIFont fontWithName:@"YOUR FONT's NAME" size:16];
gettingSizeLabel.text = @"YOUR LABEL's TEXT";
gettingSizeLabel.numberOfLines = 0;
gettingSizeLabel.lineBreakMode = NSLineBreakByWordWrapping;
CGSize maximumLabelSize = CGSizeMake(310, CGFLOAT_MAX);

CGSize expectSize = [gettingSizeLabel sizeThatFits:maximumLabelSize];

Edycja: ten górny kod nie jest dobry dla iOS 7 i nowszych, więc użyj poniżej:

CGRect textRect = [myString boundingRectWithSize:maximumLabelSize   
                         options:NSStringDrawingUsesLineFragmentOrigin| NSStringDrawingUsesFontLeading
                         attributes:@{NSFontAttributeName:fontText}
                         context:nil];
Quang Hà
źródło
ta metoda nie działa, gdy dodam jednostki HTML, takie jak (<OL>, <LI>) w ciągu.
Nirav Jain
proszę ponownie sprawdzić moją odpowiedź! Brakuje mi właściwości numberOfLines! Przepraszam!
Quang Ha
1
Po wielu godzinach poszukiwań, eksperymentów i ślepych zaułków jest to jedyne rozwiązanie, które działa na iOS7 i Xamarin / Monotouch
Michael Rodrigues
26
Tworzysz etykietę do obliczania rozmiaru czcionki? To takie marnotrawstwo!
Ossir
13
@Ossir, czy masz lepszy pomysł?
Luda
36

Może trzeba podać dodatkową opcję do metody, która jest sugerowana w tej odpowiedzi:

CGSize maximumLabelSize = CGSizeMake(310, CGFLOAT_MAX);
CGRect textRect = [myString boundingRectWithSize:maximumLabelSize   
                                         options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
                                      attributes:@{NSFontAttributeName: fontText}
                                         context:nil];
Maxim Pavlov
źródło
3
Wygląda na boundingRectWithSizeto, że jest uszkodzony. Testowałem na iOS 7, 7.1.1 i zwraca nieprawidłowe wyniki.
RaffAl
To nie zadziałało, ale użycie boundingRectWithSize na NSAttributedString i dodanie mojego atrybutu czcionki do ciągu działało.
Sheepdogsheep
12
Chłopaki, nie zapominajcie o instrukcji Apple: W iOS 7 i nowszych ta metoda zwraca rozmiary ułamkowe (w składniku size zwróconego CGRect); aby użyć zwróconego rozmiaru do rozmiaru widoków, należy podnieść jego wartość do najbliższej większej liczby całkowitej za pomocą funkcji ceil.
SoftDesigner
2
ceil mi nie wystarczał, ale stwierdziłem, że użycie ceil i dodanie 0,5
załatwiło sprawę
15

Oto mój działający fragment kodu:

NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:attributeDict];

NSString *headline  = [dict objectForKey:@"title"];  
UIFont *font        = [UIFont boldSystemFontOfSize:18];  
CGRect  rect        = [headline boundingRectWithSize:CGSizeMake(300, 1000) options:NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading attributes:@{NSFontAttributeName:font} context:nil];

CGFloat height      = roundf(rect.size.height +4)

Dodałem 4px do wyliczonej wysokości, bo bez tych 4px brakuje jednej linii.

Używam tego fragmentu kodu w tableView i dodaję „wysokość” do tablicy NSNumbers i otrzymuję poprawną wysokość komórki dla domyślnego textLabel.

Dodaj 4 więcej pikseli, jeśli chcesz mieć więcej miejsca pod tekstem w textLabel.

**** AKTUALIZACJA ****

Nie zgadzam się z „błędem szerokości 40px”, krzyczę jako 4px brakującej wysokości, ponieważ 4px to domyślna wysokość odstępu między literą a granicą jednej linii. Możesz to sprawdzić za pomocą UILabel, dla rozmiaru czcionki 16 potrzebujesz UILabel wysokości 20.

Ale jeśli ostatnia linia nie zawiera „g” lub czegokolwiek innego, pomiar może nie mieć 4 piks. Wysokości.

Ponownie sprawdziłem to małą metodą, otrzymałem dokładną wysokość 20,40 lub 60 dla mojej etykiety i odpowiednią szerokość mniejszą niż 300 pikseli.

Aby obsługiwać iOS6 i iOS7, możesz użyć mojej metody:

- (CGFloat)heightFromString:(NSString*)text withFont:(UIFont*)font constraintToWidth:(CGFloat)width
{
    CGRect rect;

    float iosVersion = [[[UIDevice currentDevice] systemVersion] floatValue];
    if (iosVersion >= 7.0) {
        rect = [text boundingRectWithSize:CGSizeMake(width, 1000) options:NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading attributes:@{NSFontAttributeName:font} context:nil];
    }
    else {
        CGSize size = [text sizeWithFont:font constrainedToSize:CGSizeMake(width, 1000) lineBreakMode:NSLineBreakByWordWrapping];
        rect = CGRectMake(0, 0, size.width, size.height);
    }
    NSLog(@"%@: W: %.f, H: %.f", self, rect.size.width, rect.size.height);
    return rect.size.height;
}

**** AKTUALIZACJA ****

Dzięki waszym komentarzom zaktualizowałem moją funkcję w następujący sposób. Ponieważ sizeWithFont jest przestarzałe i otrzymasz ostrzeżenie w XCode, dodałem diagnostyczny kod pragma, aby usunąć ostrzeżenie dla tego konkretnego wywołania funkcji / bloku kodu.

- (CGFloat)heightFromStringWithFont:(UIFont*)font constraintToWidth:(CGFloat)width
{
    CGRect rect;

    if ([self respondsToSelector:@selector(boundingRectWithSize:options:attributes:context:)]) {
        rect = [self boundingRectWithSize:CGSizeMake(width, 1000) options:NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading attributes:@{NSFontAttributeName:font} context:nil];
    }
    else {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
        CGSize size = [self sizeWithFont:font constrainedToSize:CGSizeMake(width, 1000) lineBreakMode:NSLineBreakByWordWrapping];
        rect = CGRectMake(0, 0, size.width, size.height);
#pragma GCC diagnostic pop
    }
    return ceil(rect.size.height);
}

Oprócz tematu 4px: w zależności od używanej czcionki i grubości czcionki obliczenie zwraca różne wartości wysokości. W moim przypadku: HelveticaNeue-Medium z rozmiarem czcionki 16,0 zwraca wysokość linii 20,0 dla jednego wiersza, ale 39,0 dla dwóch wierszy, 78 pikseli dla 4 wierszy -> brak 1 piksela dla każdego wiersza - zaczynając od wiersza 2 - ale chcesz aby mieć rozmiar czcionki + 4 piksele odstępów między wierszami dla każdej linii, musisz otrzymać wynik wysokości.
Pamiętaj o tym podczas kodowania!
Nie mam jeszcze funkcji dla tego "problemu", ale zaktualizuję ten post, kiedy skończę.

Rikco
źródło
1
Prawdopodobnie powinieneś używać [text respondsToSelector: @selector (boundingRectWithSize: options: attribute: context :)] zamiast sprawdzać wartość typu float.
Samah
1
Lepiej jest użyć funkcji ceil zamiast + 4pkt, spójrz na tę odpowiedź stackoverflow.com/a/23563152/667483
surfrider
2

Jeśli dobrze rozumiem, używasz boundingRectWithSize: tylko jako sposób na uzyskanie rozmiaru, który uzyskasz dzięki sizeWithFont (co oznacza, że ​​chcesz bezpośrednio CGSize, a nie CGRect)?

To wygląda na to, czego szukasz:

Zamiennik dla przestarzałego sizeWithFont: w iOS 7?

Używają sizeWithAttributes: aby uzyskać rozmiar, jako zamiennik sizeWithFont.

Czy nadal otrzymujesz zły rozmiar, używając czegoś takiego:

UIFont *fontText = [UIFont fontWithName:[AppHandlers zHandler].fontName size:16];
                    // you can use your font.

expectedLabelSize = [myString sizeWithAttributes:@{NSFontAttributeName:fontText}];
vinaut
źródło
ale jak mogę użyć CGSize maximumLabelSize = CGSizeMake (310, 9999)? Potrzebuję odpowiedniej wysokości i szerokości.
Nirav Jain,
1
Czy są jakieś atrybuty, które mówią sizeWithAttributes:, aby ograniczyć jego szerokość / wysokość?
Nirav Jain
Przepraszam, ale nie rozumiem, w czym jest twój problem. Chcesz dopasować rozmiar etykiety do rozmiaru czcionki, ale nie więcej niż maksymalna wysokość, jeśli dobrze rozumiem. Mówisz, że możesz to zrobić z sizeWithFont, ale teraz, gdy ta metoda jest przestarzała, potrzebujesz alternatywy, prawda? Powinieneś móc podłączyć sizeWithAttribues: w ten sam sposób, w jaki używałeś sizeWithFont:. W jaki sposób ograniczałeś rozmiar etykiety, używając sizeWithFont? Czy możesz opublikować kod, który działał dla Ciebie, używając sizeWithFont?
vinaut
2
Używał sizeWithFont: constrainedToSize: lineBreakMode: i nie ma możliwości przekazania wartości constrainedToSize do sizeWithAttributes.
zh.
2

Komentarz @ SoftDesigner zadziałał dla mnie

CGRect descriptionRect = [description boundingRectWithSize:CGSizeMake(width, 0)
                                                       options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
                                                    attributes:@{NSFontAttributeName : [UIFont systemFontOfSize:12]}
                                                       context:nil];
result = ceil(descriptionRect.size.height);
Myrddin
źródło
1

do znajdowania rozmiaru czasu działania etykiety czcionki jest przestarzały w systemie iOS 7.0, zamiast tego należy użyć -boundingRectWithSize: opcje: atrybuty: kontekst: metoda

Możesz go użyć jak poniżej kodu

CGSize constraint = CGSizeMake(MAXIMUM_WIDHT, TEMP_HEIGHT);
NSRange range = NSMakeRange(0, [[self.message body] length]);

NSDictionary *attributes = [YOUR_LABEL.attributedText attributesAtIndex:0 effectiveRange:&range];
CGSize boundingBox = [myString boundingRectWithSize:constraint options:NSStringDrawingUsesFontLeading attributes:attributes context:nil].size;
int numberOfLine = ceil((boundingBox.width) / YOUR_LABEL.frame.size.width);
CGSize descSize = CGSizeMake(ceil(boundingBox.width), ceil(self.lblMessageDetail.frame.size.height*numberOfLine));

CGRect frame=YOUR_LABEL.frame;
frame.size.height=descSize.height;
YOUR_LABEL.frame=frame;

tutaj musisz podać szerokość do maksymalnej długości, aby znaleźć wysokość lub szerokość.

spróbuj tego, to działa dla mnie.

Pratik
źródło