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?


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

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

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ę.


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

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

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.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.