2013-08-19 13 views
26

Mam metoda, która daje mi idealny rozmiar dla UITextView danej długości łańcucha (z odpowiednim właściwym rozmiarze czcionki):Z czym powinienem zastąpić przestarzałą metodę sizeWithFont:?

- (NSInteger) heightOfLabel:(NSString*) string { 
    CGSize maximumLabelSize = CGSizeMake([[UIScreen mainScreen] bounds].size.width - 40, FLT_MAX); 
    CGSize expectedLabelSize = [[NSString stringTrimmedForLeadingAndTrailingWhiteSpacesFromString:string] 
      sizeWithFont:[UIFont systemFontOfSize:15] 
      constrainedToSize:maximumLabelSize 
      lineBreakMode:NSLineBreakByWordWrapping]; 

    return expectedLabelSize.height + 5; 
} 

W rzeczywistości, to nadal daje mi doskonałe dopasowanie, nawet w iOS7 . Chociaż teraz pojawia się metoda ostrzegania, która mówi, że nie powinienem używać "sizeWithFont: contrainedToSize: lineBreakMode".

on teraz mówi, że należy używać -boundingRectWithSize: opcje: atrybuty: kontekst:

Metoda ta nie jest nowością iOS7 a zatem zorientować, że jest w porządku, aby poprosić go na przepełnienie stosu, a nie będzie na oficjalnym forum twórców jabłek.

Mam trzy pytania:

1) Bo to jest przestarzała, to znaczy, należy wymienić go na pewno, mimo to nadal działa?

2) Próbowałem wiele różnych metod boundingRectWithSize: z różnymi zmiennymi, ale nigdy nie jest doskonały, zawsze wydaje się być nieco na zewnątrz (jak wiele pytań stackoverflow wskazuje) - czy istnieje doskonały zamiennik tego niezaakceptowanego metoda, która działa dokładnie tak samo jak moja poprzednia metoda, przy minimalnym wysiłku?

3) po co usuwać tę metodę? Czy to z powodu nakładania się tej drugiej metody?

+0

sprawdź to [link] (http://www.cnblogs.com/lisa090818/p/3445161.html). – yazh

+1

wtf to ten link? – Rambatino

Odpowiedz

57

Po godzinie błędu próby udało mi się zrobić to praca:

CGSize maximumLabelSize = CGSizeMake(tableView.width, MAXFLOAT); 

NSStringDrawingOptions options = NSStringDrawingTruncatesLastVisibleLine | 
           NSStringDrawingUsesLineFragmentOrigin; 

NSDictionary *attr = @{NSFontAttributeName: [UIFont systemFontOfSize:15]}; 
CGRect labelBounds = [string boundingRectWithSize:maximumLabelSize 
              options:options 
             attributes:attr 
              context:nil]; 

Aktualizacja:

Jak Pan wspomina T w odpowiedzi poniżej: w iOS 7 i nowszych, ta metoda zwraca ułamkowe rozmiary (w komponencie wielkości zwróconego CGRect); aby użyć zwróconych do rozmiaru widoków, należy użyć jego wartości do najbliższej większej liczby całkowitej za pomocą funkcji ceil. Zaleca się użycie funkcjiceilf.

CGFloat height = ceilf(labelBounds.size.height); 
+1

Dziękuję za to. Używam teraz czegoś podobnego do iOS6, który tworzy NSAttributedString używając słownika stringAttributes, który tworzysz i wywołuje boundingRectWithSize: options: context: na przypisanym łańcuchu. – AidenMontgomery

+0

Niż ty! Naprawdę użyteczne! – Andres

13

Wierzę, że funkcja została zaniechana z powodu, że seria funkcji NSString + UIKit były oparte na bibliotece UIStringDrawing, która nie została wątku bezpieczne. Jeśli próbowałeś uruchomić je nie w głównym wątku (jak w przypadku każdej innej funkcji UIKit), dostaniesz nieprzewidywalne zachowania. W szczególności, jeśli uruchomisz funkcję na wielu wątkach jednocześnie, prawdopodobnie spowoduje to awarię aplikacji. Dlatego w iOS 6 wprowadzono metodę NSAttributedStrings w postaci boundingRectWithSize:.... Zostało to zbudowane na bibliotekach NSStringDrawing i jest bezpieczne dla wątków.

Jeśli spojrzysz na nową funkcję NSString boundingRectWithSize:..., prosi o tablicę atrybutów w taki sam sposób jak NSAttributeString. Gdybym miał zgadywać, ta nowa funkcja NSString w iOS 7 jest tylko opakowaniem dla funkcji NSAttributeString z iOS 6.

W tej notatce, gdybyś wspierał tylko iOS 6 i iOS 7, zdecydowanie zmieniłbym wszystkie twojego NSStringa sizeWithFont:... do NSAttributeString's boundingRectWithSize. To pozwoli Ci zaoszczędzić wiele bólu głowy, jeśli masz dziwną, wielowątkową skrzynkę narożną!Oto jak ja konwertowane NSString na sizeWithFont:constrainedToSize::

Co kiedyś:

NSString *text = ...; 
CGFloat width = ...; 
UIFont *font = ...; 
CGSize size = [text sizeWithFont:font 
       constrainedToSize:CGSizeMake(width, CGFLOAT_MAX)]; 

można zastąpić:

NSString *text = ...; 
CGFloat width = ...; 
UIFont *font = ...; 
NSAttributedString *attributedText = 
    [[NSAttributedString alloc] 
     initWithString:text 
     attributes:@ 
     { 
      NSFontAttributeName: font 
     }]; 
CGRect rect = [attributedText boundingRectWithSize:CGSizeMake(width, CGFLOAT_MAX) 
              options:NSStringDrawingUsesLineFragmentOrigin 
              context:nil]; 
CGSize size = rect.size; 

Uwaga dokumentacji wspomina:

w iOS 7 i później ta metoda zwraca rozmiary ułamkowe (w rozmiarze komponentu zwróconego CGRect); Aby użyć zwróconych rozmiarów do rozmiarów , należy użyć zwiększenia wartości do najbliższej większej liczby całkowitej za pomocą funkcji ceil.

więc wyciągnąć wysokość obliczoną lub szerokość ma być używany do zaklejania widoki, chciałbym używać:

CGFloat height = ceilf(size.height); 
CGFloat width = ceilf(size.width); 
+4

doesnt address linebreakmode issue – Firdous

+0

Zobacz moją odpowiedź poniżej. –

5

Dla lineBreak numerze:

- (CGFloat)heightNeededForText:(NSString *)text withFont:(UIFont *)font width:(CGFloat)width lineBreakMode:(NSLineBreakMode)lineBreakMode { 
    NSMutableParagraphStyle * paragraphStyle = [[NSMutableParagraphStyle alloc] init]; 
     paragraphStyle.lineBreakMode = lineBreakMode; 
    CGSize size = [text boundingRectWithSize:CGSizeMake(width, CGFLOAT_MAX) 
            options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading) 
            attributes:@{ NSFontAttributeName: font, NSParagraphStyleAttributeName: paragraphStyle } 
            context:nil].size; 

    return ceilf(size.height); 
} 
2

Swift wersję Odpowiedź Alexandra z Norwegii ...

func heightNeededForText(text: NSString, withFont font: UIFont, width: CGFloat, lineBreakMode:NSLineBreakMode) -> CGFloat { 
     let paragraphStyle = NSMutableParagraphStyle() 
     paragraphStyle.lineBreakMode = lineBreakMode 
     let size: CGSize = text.boundingRectWithSize(CGSizeMake(width, CGFloat.max), options: [.UsesLineFragmentOrigin, .UsesFontLeading], attributes: [ NSFontAttributeName: font, NSParagraphStyleAttributeName: paragraphStyle], context: nil).size//text boundingRectWithSize:CGSizeMake(width, CGFLOAT_MA 

     return ceil(size.height); 
    } 

W kodzie, w którym chcesz, aby uzyskać wysokość tylko wywołać metodę jak poniżej ...

let size = self.heightNeededForText(text as NSString, withFont: UIFont.systemFontOfSize(15.0), width: scrollView.frame.size.width - 20, lineBreakMode: NSLineBreakMode.ByWordWrapping) //Can edit the font size and LinebreakMode 
Powiązane problemy