2012-01-30 19 views

Odpowiedz

39

Ci ludzie znaleźli rozwiązanie:

http://www.11pixel.com/blog/28/resize-multi-line-text-to-fit-uilabel-on-iphone/

Ich rozwiązanie jest następujące:

int maxDesiredFontSize = 28; 
int minFontSize = 10; 
CGFloat labelWidth = 260.0f; 
CGFloat labelRequiredHeight = 180.0f; 
//Create a string with the text we want to display. 
self.ourText = @"This is your variable-length string. Assign it any way you want!"; 

/* This is where we define the ideal font that the Label wants to use. 
    Use the font you want to use and the largest font size you want to use. */ 
UIFont *font = [UIFont fontWithName:@"Marker Felt" size:maxDesiredFontSize]; 

int i; 
/* Time to calculate the needed font size. 
    This for loop starts at the largest font size, and decreases by two point sizes (i=i-2) 
    Until it either hits a size that will fit or hits the minimum size we want to allow (i > 10) */ 
for(i = maxDesiredFontSize; i > minFontSize; i=i-2) 
{ 
    // Set the new font size. 
    font = [font fontWithSize:i]; 
    // You can log the size you're trying: NSLog(@"Trying size: %u", i); 

    /* This step is important: We make a constraint box 
     using only the fixed WIDTH of the UILabel. The height will 
     be checked later. */ 
    CGSize constraintSize = CGSizeMake(labelWidth, MAXFLOAT); 

    // This step checks how tall the label would be with the desired font. 
    CGSize labelSize = [self.ourText sizeWithFont:font constrainedToSize:constraintSize lineBreakMode:UILineBreakModeWordWrap]; 

    /* Here is where you use the height requirement! 
     Set the value in the if statement to the height of your UILabel 
     If the label fits into your required height, it will break the loop 
     and use that font size. */ 
    if(labelSize.height <= labelRequiredHeight) 
     break; 
} 
// You can see what size the function is using by outputting: NSLog(@"Best size is: %u", i); 

// Set the UILabel's font to the newly adjusted font. 
msg.font = font; 

// Put the text into the UILabel outlet variable. 
msg.text = self.ourText; 

W celu uzyskania tej pracy, o IBOutlet musi być przypisany w konstruktora interfejsu do UILabel.

"IBOutlet UILabel * msg;"

Wszystko jest zasługą ludzi w 11pixel.

+0

Nie działa dla mnie. –

46

I zmodyfikowany powyższy kod nieco aby to kategoria na UILabel: file

Header:

#import <UIKit/UIKit.h> 
@interface UILabel (MultiLineAutoSize) 
    - (void)adjustFontSizeToFit; 
@end 

a plik realizacja:

@implementation UILabel (MultiLineAutoSize) 

- (void)adjustFontSizeToFit 
{ 
    UIFont *font = self.font; 
    CGSize size = self.frame.size; 

    for (CGFloat maxSize = self.font.pointSize; maxSize >= self.minimumFontSize; maxSize -= 1.f) 
    { 
     font = [font fontWithSize:maxSize]; 
     CGSize constraintSize = CGSizeMake(size.width, MAXFLOAT); 
     CGSize labelSize = [self.text sizeWithFont:font constrainedToSize:constraintSize lineBreakMode:UILineBreakModeWordWrap]; 
     if(labelSize.height <= size.height) 
     { 
      self.font = font; 
      [self setNeedsLayout]; 
      break; 
     } 
    } 
    // set the font to the minimum size anyway 
    self.font = font; 
    [self setNeedsLayout]; 
} 

@end 
+0

Wspaniale, potknąłem się o to samo i to rozwiązuje w mgnieniu oka :-) Tylko dwie uwagi: ** (1) ** pierwsze dwie linie w wewnętrznej klauzuli "jeśli" są zbędne, ponieważ będą wykonywane tuż pod cyklem "za". ** (2) ** jeśli istnieje potrzeba, aby tekst UILabel był pionowo wyrównany do góry (w przypadku, gdy używa on mniej linii niż faktycznie może być pokazany na etykiecie), wystarczy ustawić wysokość etykiety na labelSize.height. Zauważ, że sizeToFit nie może być użyte do tego celu, ponieważ łamie wcześniej sformatowany tekst i dopasowuje go do oryginalnego rozmiaru czcionki. – FurloSK

+5

To jest idealne, ale metoda minimalnaFontSize jest przestarzała w systemie iOS6 - jak można to zmienić, aby działała z minimalnym współczynnikiem skali? – bmueller

+0

Właśnie tego potrzebowałem. Dzięki. +1 –

6

Podobało mi odpowiedź DaGaMs, ale w używaniu etykiet, takich jak w komórkach UITableViewCell, które mogą być zwrócone przez dequeueReusableCell :, zwykły rozmiar czcionki będzie się zmniejszał nawet w rozmiarze oryginalnym było nadal pożądane w przypadku niektórych komórek tableView, które zawierały mniej tekstu i mogły korzystać z oryginalnego rozmiaru czcionki oryginalnej etykiety.

Więc zaczynając kategorii DaGaMs jako baza wypadowa, i stworzył oddzielną klasę zamiast odrębną kategorię, i upewnić się, moje UILabels w moim serii ujęć skorzystać z tej nowej klasy:

#import "MultiLineAutoShrinkLabel.h" 

@interface MultiLineAutoShrinkLabel() 
@property (readonly, nonatomic) UIFont* originalFont; 
@end 

@implementation MultiLineAutoShrinkLabel 

@synthesize originalFont = _originalFont; 

- (UIFont*)originalFont { return _originalFont ? _originalFont : (_originalFont = self.font); } 

- (void)quoteAutoshrinkUnquote 
{ 
    UIFont* font = self.originalFont; 
    CGSize frameSize = self.frame.size; 

    CGFloat testFontSize = _originalFont.pointSize; 
    for (; testFontSize >= self.minimumFontSize; testFontSize -= 0.5) 
    { 
     CGSize constraintSize = CGSizeMake(frameSize.width, MAXFLOAT); 
     CGSize testFrameSize = [self.text sizeWithFont:(font = [font fontWithSize:testFontSize]) 
            constrainedToSize:constraintSize 
             lineBreakMode:self.lineBreakMode]; 
     // the ratio of testFontSize to original font-size sort of accounts for number of lines 
     if (testFrameSize.height <= frameSize.height * (testFontSize/_originalFont.pointSize)) 
      break; 
    } 

    self.font = font; 
    [self setNeedsLayout]; 
} 

@end 
+1

+1 za radzenie sobie z UITableViewCells. Ale gdzie jest kod dla twojego interfejsu MultilineAutoShrinkLabel.h? – Rhubarb

+0

@Rhubarb, to po prostu trywialne: podklasa UILabel z jedną funkcją, '- (void) quoteAutoshrinkUnquote;' ... i faktycznie, przeszedłem do użycia czegoś podobnego, ale nieco bardziej skomplikowanego, co dotyczy akcesorium po prawej stronie oraz fakt, że może to być 2 różne rozmiary, pozwalające na mniej lub bardziej ekranową nieruchomość na komórkę. –

+0

Użyłem tej odpowiedzi, aby odpowiedzieć na moją własną wersję, a także zaktualizowałem kod, aby usunąć nieaktualne metody. Http://stackoverflow.com/a/30898604/758083 – Hackmodford

4

Dziękuję DaGaM za to rozwiązanie.

zaktualizowałem go w następujący sposób:

1 - Aby pracować z iOS 6 (ponieważ oba minimumFontSize i UILineBreakModeWordWrap są przestarzałe) 2 - Aby rozebrać spacje z tekstu etykiety, ponieważ spowoduje to zmianę rozmiaru do fail (nie chcesz wiedzieć, jak długo zajęło mi znaleźć ten błąd) odpowiedź

-(void)adjustFontSizeToFit 
{ 
    self.text = [self.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; 

    UIFont *font = self.font; 
    CGSize size = self.frame.size; 

    for (CGFloat maxSize = self.font.pointSize; maxSize >= self.minimumScaleFactor; maxSize -= 1.f) 
    { 
     font = [font fontWithSize:maxSize]; 
     CGSize constraintSize = CGSizeMake(size.width, MAXFLOAT); 
     CGSize labelSize = [self.text sizeWithFont:font constrainedToSize:constraintSize lineBreakMode:NSLineBreakByWordWrapping]; 
     if(labelSize.height <= size.height) 
     { 
      self.font = font; 
      [self setNeedsLayout]; 
      break; 
     } 
    } 
    // set the font to the minimum size anyway 
    self.font = font; 
    [self setNeedsLayout]; 
} 
+2

'minimumScaleFactor' ma wartość dziesiętną, np. 0,2. 'maxSize> = self.minimumScaleFactor' zmniejszy rozmiar do 0.2. Zamiast tego nie chcesz "maxSize> = self.minimumScaleFactor * self.font.pointSize" lub coś podobnego? – pwightman

6

itedcedor zawiera błąd, który pwightman zauważył. Ponadto nie ma potrzeby przycinania białych znaków. Oto zmodyfikowana wersja:

- (void)adjustFontSizeToFit { 
    UIFont *font = self.font; 
    CGSize size = self.frame.size; 

    for (CGFloat maxSize = self.font.pointSize; maxSize >= self.minimumScaleFactor * self.font.pointSize; maxSize -= 1.f) { 
     font = [font fontWithSize:maxSize]; 
     CGSize constraintSize = CGSizeMake(size.width, MAXFLOAT); 
     CGSize labelSize = [self.text sizeWithFont:font constrainedToSize:constraintSize lineBreakMode:NSLineBreakByWordWrapping]; 

     if(labelSize.height <= size.height) { 
      self.font = font; 
      [self setNeedsLayout]; 
      break; 
     } 
    } 

    // set the font to the minimum size anyway 
    self.font = font; 
    [self setNeedsLayout]; 
} 
+0

Problem, z którym się borykam, polega na tym, że tekst wydaje się wyrównany do lewej niezależnie od tego, co robisz. Aktualizacja: Wygląda na odznaczenie "Zaostrzyć odstęp między literami" rozwiązuje ten problem. – Pierre

24

Oto rozwiązanie kategorii zaktualizowane do iOS 7 w oparciu o aktualizacje itecedor dla iOS 6.

plik nagłówka:

#import <UIKit/UIKit.h> 
@interface UILabel (MultiLineAutoSize) 
    - (void)adjustFontSizeToFit; 
@end 

a plik realizacja:

@implementation UILabel (MultiLineAutoSize) 


- (void)adjustFontSizeToFit { 
    UIFont *font = self.font; 
    CGSize size = self.frame.size; 

    for (CGFloat maxSize = self.font.pointSize; maxSize >= self.minimumScaleFactor * self.font.pointSize; maxSize -= 1.f) 
    { 
     font = [font fontWithSize:maxSize]; 
     CGSize constraintSize = CGSizeMake(size.width, MAXFLOAT); 

     CGRect textRect = [self.text boundingRectWithSize:constraintSize 
              options:NSStringDrawingUsesLineFragmentOrigin 
              attributes:@{NSFontAttributeName:font} 
              context:nil]; 

     CGSize labelSize = textRect.size; 


     if(labelSize.height <= size.height) 
     { 
      self.font = font; 
      [self setNeedsLayout]; 
      break; 
     } 
    } 
    // set the font to the minimum size anyway 
    self.font = font; 
    [self setNeedsLayout]; } 


@end 
+2

Nie trzeba stosować minimalnego Współczynnika Skalowania do początkowej wielkości punktu? (np. jeśli współczynnik wynosi 0.5, możesz tu uzyskać bardzo małe czcionki). – iceydee

+0

Masz rację! Będę edytować odpowiedź, aby to odzwierciedlić. – stevenpaulr

+1

Działa jak urok, nie zapomnij ustawić adjustsFontSizeToFitWidth na TAK dla UILabel –

0

Istnieje metoda na NSString, -sizeWithFont:minFontSize:actualFontSize:forWidth:lineBreakMode: który najwyraźniej istnieje od iOS 2.0, ale niestety jest przestarzałe w iOS 7 bez sugerowana alternatywa, ponieważ odradza się automatyczne zmniejszanie rozmiaru czcionki. Naprawdę nie rozumiem stanowiska firmy Apple w tej kwestii, ponieważ używają tego w głównym tekście itd. I myślę, że jeśli rozmiary czcionek mieszczą się w niewielkim zakresie, to jest w porządku. Oto implementacja w Swift przy użyciu tej metody.

var newFontSize: CGFloat = 30 
    let font = UIFont.systemFontOfSize(newFontSize) 
    (self.label.text as NSString).sizeWithFont(font, minFontSize: 20, actualFontSize: &newFontSize, forWidth: self.label.frame.size.width, lineBreakMode: NSLineBreakMode.ByWordWrapping) 
    self.label.font = font.fontWithSize(newFontSize) 

Nie jestem świadomy sposobu, w jaki można to osiągnąć bez użycia przestarzałych metod.

7

Szybka wersja zaadaptowana z @DaGaMs.

Swift 2:

extension UILabel { 
    func adjustFontSizeToFit(minimumFontSize: CGFloat, maximumFontSize: CGFloat? = nil) { 
     let maxFontSize = maximumFontSize ?? font.pointSize 
     for size in stride(from: maxFontSize, to: minimumFontSize, by: -CGFloat(0.1)) { 
      let proposedFont = font.fontWithSize(size) 
      let constraintSize = CGSizeMake(bounds.size.width, CGFloat(MAXFLOAT)) 
      let labelSize = ((text ?? "") as NSString).boundingRectWithSize(constraintSize, 
       options: .UsesLineFragmentOrigin, 
       attributes: [NSFontAttributeName: proposedFont], 
       context: nil) 
      if labelSize.height <= bounds.size.height { 
       font = proposedFont 
       setNeedsLayout() 
       break; 
      } 
     } 
    } 
} 

SWIFT 3:

extension UILabel { 
    func adjustFontSizeToFit(minimumFontSize: CGFloat, maximumFontSize: CGFloat? = nil) { 
     let maxFontSize = maximumFontSize ?? font.pointSize 
     for size in stride(from: maxFontSize, to: minimumFontSize, by: -CGFloat(0.1)) { 
      let proposedFont = font.withSize(size) 
      let constraintSize = CGSize(width: bounds.size.width, height: CGFloat(MAXFLOAT)) 
      let labelSize = ((text ?? "") as NSString).boundingRect(with: constraintSize, 
                      options: .usesLineFragmentOrigin, 
                      attributes: [NSFontAttributeName: proposedFont], 
                      context: nil) 
      if labelSize.height <= bounds.size.height { 
       font = proposedFont 
       setNeedsLayout() 
       break; 
      } 
     } 
    } 
} 
+0

Nie działa w ogóle –

8

Odpowiedź oznaczony jako rozwiązania jest hacky i niedokładne. UILabel będzie je obsługiwać automatycznie jeśli ustawić następujące właściwości poprawnie:

numberOfLines musi być niezerowe

adjustsFontSizeToFitWidth musi być YES

lineBreakMode koniecznością nie być NSLineBreakByCharWrapping lub NSLineBreakByWordWrapping

+1

Udało mi się użyć: numberOfLines = 0, lineBreakMode = NSLineBreakByTruncatingTail (lub NSLineBreakByTruncatingHead lub NSLineBreakByTruncatingMiddle) z ograniczeniem wysokości na etykiecie. –

+0

To powinna być zaakceptowana odpowiedź. –

29

znalazłem ten link http://beckyhansmeyer.com/2015/04/09/autoshrinking-text-in-a-multiline-uilabel/

Problem można rozwiązać za pomocą Kreatora interfejsu w 3 prostych krokach: „Minimalny rozmiar czcionki”

  1. Set „autoshrink” do
  2. Ustaw czcionkę do swojej największego pożądanego rozmiaru czcionki (20) i ustawić Linie do, powiedzmy, 10, które w moim przypadku były tak liczne, jak pasowałyby do etykiety przy tym rozmiarze czcionki.
  3. Następnie zmiana „Linia Breaks” z „zawijania” do „Obetnij Tail”.

Nadzieję, że to pomaga!

+0

Wybieram Truncate Tail, a moje niewidzialne linie są teraz widoczne. – EFE

+1

O wiele lepsze rozwiązanie niż niestandardowy kod. Dobra robota. – Kris

+0

Dziękuję za wskazanie "ściętego ogona", to robi różnicę. –

2

Dla UIButton, tylko te linie pracują dla mnie:

self.centerBtn.titleLabel.numberOfLines = 2; 
self.centerBtn.titleLabel.textAlignment = NSTextAlignmentCenter; 
self.centerBtn.titleLabel.adjustsFontSizeToFitWidth = YES; 
7

nie mogę skomentować stanowisko MontiRabbit powodu reputacji brakuje, więc zrobię nową odpowiedź.Rozwiązanie, które zaproponował (i jej polecający) nie działa na Xcode 7.3 lub lepszym, jest nieprecyzyjne. Aby działać w ujęć, miałem:

  1. ustawiona szerokość ograniczenie (czysty szerokość lub ogon & ołowiu)
  2. SET się ograniczenia do wysokości (to jest bardzo ważne, zazwyczaj AUTORESIZE nie ma ustawić wysokość etykiety)
  3. set „autoshrink” własność do „Minimalna waga czcionki” lub „Minimalny rozmiar czcionki” (prace w obu przypadkach)
  4. set „Linia Breaks” własność do „Obetnij ogon”
  5. set " Linie "do niezerowej wartości

Mam nadzieję, że pomoże! ;)

+0

Ustawienie linii Przerwanie na "Obcinanie ogona" jest sprzeczne z intuicją, nie powinno być konieczne i powoduje, że magia nagle ma miejsce, gdy wszystko inne ustawia się tak, jak tego oczekujesz. Dzięki! Potwierdzenie ograniczenia wysokości nie musi być stałą wysokością, może po prostu dołączyć ją do rozmiaru kontenera lub jego części. –

+0

@DuncanBabbage, nie ma za co! Możemy więc powiedzieć, że wysokość etykiety musiała być obliczana przez kompilator, w jakiś sposób z ograniczeniem wysokości lub z referencją rodzica! – Nem

0

Użyłem rozwiązania Swift 3 @ wbarksdale, ale stwierdziłem, że długie słowa zostały obcięte w środku. Aby zachować słowa nienaruszone, musiałem zmodyfikować w następujący sposób:

extension UILabel { 
    func adjustFontSizeToFit(minimumFontSize: CGFloat, maximumFontSize: CGFloat? = nil) { 
     let maxFontSize = maximumFontSize ?? font.pointSize 
     let words = self.text?.components(separatedBy: " ") 
     var longestWord: String? 
     if let max = words?.max(by: {$1.characters.count > $0.characters.count}) { 
      longestWord = max 
     } 
     for size in stride(from: maxFontSize, to: minimumFontSize, by: -CGFloat(0.1)) { 
      let proposedFont = font.withSize(size) 
      let constraintSize = CGSize(width: bounds.size.width, height: CGFloat(MAXFLOAT)) 
      let labelSize = ((text ?? "") as NSString).boundingRect(with: constraintSize, 
                    options: .usesLineFragmentOrigin, 
                    attributes: [NSFontAttributeName: proposedFont], 
                    context: nil) 

      let wordConstraintSize = CGSize(width: CGFloat(MAXFLOAT), height: CGFloat(MAXFLOAT)) 
      let longestWordSize = ((longestWord ?? "") as NSString).boundingRect(with: wordConstraintSize, 
                    options: .usesFontLeading, 
                    attributes: [NSFontAttributeName: proposedFont], 
                    context: nil) 

      if labelSize.height <= bounds.size.height && longestWordSize.width < constraintSize.width { 
       font = proposedFont 
       setNeedsLayout() 
       break 
      } 
     } 
    } 
} 
0

Spróbuj tego:

Tak czy podklasy UILabel lub zadzwoń adjustFontSize metodę po ustawieniu właściwości tekstu na etykiecie

override var text : String? { didSet { self.adjustFontSize() } } 

func adjustFontSize() 
{ 
    var lineCount = self.string.components(separatedBy: "\n").count - 1 
    var textArray = self.string.components(separatedBy: " ") 
    var wordsToCompare = 1 
    while(textArray.count > 0) 
    { 
     let words = textArray.first(n: wordsToCompare).joined(separator: " ") 
     let wordsWidth = words.widthForHeight(0, font: self.font) 
     if(wordsWidth > self.frame.width) 
     { 
      textArray.removeFirst(wordsToCompare) 
      lineCount += 1 
      wordsToCompare = 1 
     } 
     else if(wordsToCompare > textArray.count) 
     { 
      break 
     } 
     else 
     { 
      wordsToCompare += 1 
     } 
    } 
    self.numberOfLines = lineCount + 1 
} 
0
extension UILabel{ 

func adjustFont(minSize:Int, maxSize:Int){ 
    var newFont = self.font 
    for index in stride(from: maxSize, to: minSize, by: -1) { 
     newFont = UIFont.systemFont(ofSize: CGFloat(index)) 
     let size = CGSize(width: self.frame.width, height: CGFloat(Int.max)) 
     let size2 = (self.text! as NSString).boundingRect(with: size, options: [.usesLineFragmentOrigin, .usesFontLeading], attributes: [NSAttributedStringKey.font:newFont!], context: nil).size 
     if size2.height < self.frame.size.height{ 
      break 
     } 
    } 
    self.font = newFont 
} 

}

należy również przypisać wartość do właściwości numberOfLines pakietu UILabel.

Powiązane problemy