UILabel nie zmniejsza automatycznie tekstu w celu dopasowania do rozmiaru etykiety

119

Mam ten dziwny problem, a ja do czynienia z nim przez ponad 8 godzin teraz .. W zależności od sytuacji, mam do obliczenia UILabelswielkości dynamicznie,
np
mój UIViewControllerodbiera zdarzenie i zmienić UILabelsrozmiar. od większego do mniejszego. Rozmiar mojego UILabelzmniejsza się i otrzymuję odpowiedni wymagany rozmiar, ale tekst w moim UILabelpozostaje taki sam, ten sam rozmiar czcionki itp. Potrzebuję zmniejszenia czcionki, aby cały tekst pasował do formatu UILabel. Pytanie brzmi, jak dopasować tekst do mojej etykiety, autoshrinkingczy coś w tym rodzaju?

W moim xib, UILabels autoshrinkjest zaznaczone, również liczba linii jest ustawiona na 0, a także mój ciąg ma nowe symbole linii (\ n), a ja wybrałem tryb podziału linii na wordwrap. Może ktoś był w takiej samej sytuacji jak ja teraz i mógłby mi pomóc? Byłbym naprawdę wdzięczny.

Z góry dziękuję!

EDYCJA: UILabel minimalny rozmiar czcionki jest ustawiony na 10

Lukas
źródło
jaki jest minimalny rozmiar czcionki dla ustawionej przez Ciebie etykiety, dodaj.
AJPatel

Odpowiedzi:

159

Jeśli nadal szukasz lepszego rozwiązania, myślę, że tego właśnie chcesz:

Wartość logiczna wskazująca, czy należy zmniejszyć rozmiar czcionki, aby dopasować ciąg tytułu do prostokąta ograniczającego etykietę (ta właściwość jest skuteczna tylko wtedy, gdy numberOfLineswłaściwość jest ustawiona na 1).

Ustawiając tę ​​właściwość, minimumScaleFactorMUSI być również ustawiona (dobra wartość domyślna to 0,5).

Szybki

var adjustsFontSizeToFitWidth: Bool { get set }

Cel C

@property(nonatomic) BOOL adjustsFontSizeToFitWidth;

Wartość logiczna wskazująca, czy odstępy między literami powinny być dostosowywane, aby dopasować ciąg w prostokącie granic etykiety.

Szybki

var allowsDefaultTighteningForTruncation: Bool { get set }

Cel C

@property(nonatomic) BOOL allowsDefaultTighteningForTruncation;

Źródło .

lester
źródło
18
Na marginesie, minimumFontSizejest przestarzały w iOS 6.0. Użyj minimumScaleFactorzamiast tego.
lester
14
Tak, automatyczne zmniejszanie nie działa dla wielu wierszy w UILabel. Spróbuj sobie wyobrazić: masz tekst z wieloma liniami, chcesz go zmniejszyć, aby „pasował” do szerokości. Czy więc powinien zmniejszyć cały tekst, aby zmieścić się w jednej linii, czy też słowa powinny pozostać w tej samej linii i skurczyć się, aby dopasować się do każdej szerokości? To ostatnie jest najczęstszym przypadkiem, ale nie zapominaj, że słowa są również ustawione w wielu wierszach. Nawet jeśli automatyczne układanie tekstu jest wyłączone, będziesz musiał zmierzyć się z każdym wierszem tekstu o innym rozmiarze czcionki, ponieważ nie wszystkie słowa będą pasować do szerokości.
Lester
2
Myślę, że ta odpowiedź z kategorią tutaj jest całkiem dobra, może to być nawet to, co i tak zaimplementowałeś. Jest to zdecydowanie coś, czego brakuje w Apple API, a może po prostu nie widzą kurczenia się, co powinno być częstym przypadkiem użycia dla wielu wierszy statycznego tekstu .
Lester
1
cóż, tak, to dobra uwaga, ale tak czy inaczej, myślę, że jeśli ustawię liczbę linii na 0, będzie to dość jasne stwierdzenie, że może być jedna lub więcej linii. I myślę, że automatyczne skurczenie może być zniechęcone przez numery wierszy ... W każdym razie, dzięki za wyjaśnienie sprawy. Myślałem, że robię coś złego. Kategoria to dobry pomysł, myślę, że zrobię to w innym projekcie, w którym będę tego potrzebował. Dziękuję za pomoc, powodzenia;)
Lukas
4
@lester Powinien się zmniejszyć, aby cały tekst był widoczny w liczbie linii zadeklarowanej dla etykiety przy jej aktualnych wymiarach. Nie ma potrzeby, aby każda linia miała inny rozmiar. Jestem naprawdę zaskoczony, że nie może tego rozgryźć. Więc jeśli mam (potencjalnie) długi ciąg do wyświetlenia, mogę albo mieć wiele wierszy, albo automatycznie dopasować rozmiar, a nie oba. To cudowne.
devios1
125

W ten sposób otrzymuję Autoshrinkpracę UILabel (szczególnie dla wysokości dopasowania czcionki etykiet na urządzeniu 4s z 6s Plus Storyboard) w iOS 9.2, Xcode 7.2 ...

wprowadź opis obrazu tutaj

  • Liczba linii wynosi 0
  • Podziały wiersza: Klip
  • Automatyczne zmniejszanie: minimalna skala czcionki 0,25
ohho
źródło
15
To są 3 składniki potrzebne, aby etykieta faktycznie się skurczyła, brakowało mi ustawienia przerwania linii klipu. Ponadto, jeśli sąsiaduje z innymi etykietami (które również mogą się automatycznie zmniejszać), należy ustawić priorytety kompresji / przytulania lub podać wyraźne ograniczenia szerokości lub wysokości. To powinna być obecnie akceptowana odpowiedź.
Korey Hinton
3
Liczba linii zrobiła to za mnie! Dziękuję
Michael
Upewnij się, że Twoja etykieta ma wszystkie ograniczenia, zwłaszcza początkowe i końcowe.
Mashhadi
2
Próbowałem z tymi samymi opcjami w Xcode8 i okazało się, że nie działa. Proszę pomóż mi, jeśli ktoś ma na to pomysł.
Ganesh
75

minimumFontSize jest przestarzałe w iOS 6.

Więc użyj minimumScaleFactorzamiast minmimumFontSize.

lbl.adjustsFontSizeToFitWidth = YES
lbl.minimumScaleFactor = 0.5

Szybki 5

lbl.adjustsFontSizeToFitWidth = true
lbl.minimumScaleFactor = 0.5
SwiftiSwift
źródło
Dobrze odpowiedział. Rozwiązałem mój problem. Dzięki
Abdul Yasin,
1
@AntonMatosov, nie, nie działa!
Iulian Onofrei
2
Tak, działa (teraz) - jeśli również ustawisz podziały wierszy na Obcięcie ogona zamiast zawijania słów ...
TheEye
21

moim rozwiązaniem jest również boolowska label.adjustsFontSizeToFitWidth = YES; ALE. W interfejsie Builder należy ustawić opcję Zawijanie słów na „ CLIP ”. Następnie automatycznie zmniejsz etykiety. To jest bardzo ważne.

loki-e
źródło
3
Dopiero gdy zmieniłem z „Word Wrap” na „Clip”, Autoshrink działał dla mnie.
NicJ,
Kiedy zmieniłem zawijanie słów na klip, w rzeczywistości udało mi się zmienić rozmiar etykiety z zerową linią. Chłopcze, byłoby miło, gdyby to zostało udokumentowane.
DesignatedNerd
12

W Swift 3 (programowo) musiałem zrobić to:

let lbl = UILabel()
lbl.numberOfLines = 0
lbl.lineBreakMode = .byClipping
lbl.adjustsFontSizeToFitWidth = true
lbl.minimumScaleFactor = 0.5
lbl.font = UIFont.systemFont(ofSize: 15)
Naloiko Eugene
źródło
5

Możesz pisać jak

UILabel *reviews = [[UILabel alloc]initWithFrame:CGRectMake(14, 13,270,30)];//Set frame
reviews.numberOfLines=0;
reviews.textAlignment = UITextAlignmentLeft;
reviews.font = [UIFont fontWithName:@"Arial Rounded MT Bold" size:12];
reviews.textColor=[UIColor colorWithRed:0.0/255.0 green:0.0/255.0 blue:0.0/255.0 alpha:0.8]; 
reviews.backgroundColor=[UIColor clearColor];

Możesz obliczyć liczbę linii w ten sposób

CGSize maxlblSize = CGSizeMake(270,9999);
CGSize totalSize = [reviews.text sizeWithFont:reviews.font 
              constrainedToSize:maxlblSize lineBreakMode:reviews.lineBreakMode];

CGRect newFrame =reviews.frame;
newFrame.size.height = totalSize.height;
reviews.frame = newFrame;

CGFloat reviewlblheight = totalSize.height;

int lines=reviewlblheight/12;//12 is the font size of label

UILabel *lbl=[[UILabel alloc]init];
lbl.frame=CGRectMake(140,220 , 100, 25);//set frame as your requirement
lbl.font=[UIFont fontWithName:@"Arial" size:20];
[lbl setAutoresizingMask:UIViewContentModeScaleAspectFill];
[lbl setLineBreakMode:UILineBreakModeClip];
lbl.adjustsFontSizeToFitWidth=YES;//This is main for shrinking font
lbl.text=@"HelloHelloHello";

Mam nadzieję, że to ci pomoże :-) czekam na twoją odpowiedź

Birju
źródło
więc jeśli ustawisz liczbę wierszy na mojej etykiecie, tekst będzie się wtedy automatycznie zmniejszał?
Lukas
jeśli zawartość jest zbyt szeroka, zajmie następną linię
Birju
hej, zrobiłem tak, jak sugerowałeś, ale to nie działa, dlaczego liczba wierszy miałaby mi pomóc?
Lukas
masz rację, wypróbowałem to nieprzydatne, ale znalazłem rozwiązanie dla ciebie, tak moja następna odpowiedź
Birju
lbl.adjustsFontSizeToFitWidth = YES; Pracował dla mnie!
Deweloper
4

Ostatecznie nie znalazłem odpowiedzi. Myślę, że automatyczne zmniejszanie nie działa dla wielu linii. Skończyło się na tym, że skorzystałem z sugestii w tym linku: autoshrink na UILabel z wieloma liniami

Rozwiązaniem jest obliczenie wysokości tekstu przy określonej szerokości, a jeśli tekst jest większy, zmniejszenie rozmiaru czcionki, a następnie powtórzenie tej czynności, aż wysokość będzie równa lub mniejsza niż wymagany rozmiar.

Nie rozumiem, dlaczego powinno to być takie trudne do wdrożenia. Jeśli czegoś mi brakuje, wszyscy mogą mnie poprawić :)

Lukas
źródło
Podobnie jak w przypadku innych odpowiedzi tutaj, kluczową rzeczą, której brakowało, było ustawienie Zawijania słów na „Klip”. Jest to sprzeczne z intuicją, ale jest to wymagane, aby UILabel automatycznie zmniejszał się w sposób, w jaki chcesz. Działa to z wieloma wierszami UILabel.
Duncan Babbage
4

To jest dla Swift 3 z Xcode 8.2.1 (8C1002)

Najlepszym rozwiązaniem, które znalazłem, jest ustawienie stałej szerokości w Storyboard lub IB na etykiecie. Ustaw swoje ograniczenia z ograniczeniami do marginesów. W swoim viewDidLoad dodaj następujące wiersze kodu:

override func viewDidLoad() {
            super.viewDidLoad()

            label.numberOfLines = 1
            label.adjustsFontSizeToFitWidth = true
            label.minimumScaleFactor = 0.5
        }

ograniczenia etykiety do marginesu

stałe ograniczenia etykiety szerokości do marginesów

Inspektor atrybutów

Działało to jak urok i nie przelewa się do nowej linii i zmniejsza tekst, aby dopasować go do szerokości etykiety bez żadnych dziwnych problemów i działa w Swift 3.

Rob Mcelvenny
źródło
4

To świetne pytanie, ponieważ wydaje się, że byłoby to już częścią wbudowanej UIKitfunkcjonalności lub powiązanej struktury. Oto dobry wizualny przykład pytania:

Animacja zmiany rozmiaru czcionki

Nie ma łatwego sposobu na obejście tego problemu, ale na pewno jest to możliwe. Jednym ze sposobów, aby to zrobić, jest programowe wypróbowanie różnych rozmiarów czcionek, aż znajdziesz taki, który pasuje do granic widoku. Możesz to osiągnąć za pomocą boundingRect()funkcji NSStringlub NSAttributedString. Na przykład:

let string = "This is a test"
let infiniteSize = CGSize(width: CGFloat.greatestFiniteMagnitude, height:CGFloat.greatestFiniteMagnitude)
let size = string.boundingRect(with: infiniteSize, options: [], attributes: [.font: UIFont.systemFont(ofSize: avgSize)] context: nil).size

Możesz przeprowadzić wyszukiwanie binarne, aby być bardziej wydajnym niż podejście typu brute force. Istnieją również pewne kwestie, które są nieco bardziej zaangażowane, w tym prawidłowe zawijanie słów i wydajność buforowania czcionek iOS, jeśli szukasz czegoś naprawdę solidnego.

Jeśli zależy Ci tylko na łatwym wyświetlaniu tekstu na ekranie, opracowałem solidną implementację w Swift, której używam również w aplikacji produkcyjnej. Jest to UIViewpodklasa z wydajnym, automatycznym skalowaniem czcionki dla dowolnego tekstu wejściowego, w tym wielu wierszy. Aby go użyć, po prostu zrób coś takiego:

let view = AKTextView()
// Use a simple or fancy NSAttributedString
view.attributedText = .init(string: "Some text here")
// Add to the view hierarchy somewhere

Otóż ​​to! Pełne źródło można znaleźć tutaj: https://github.com/FlickType/AccessibilityKit

Mam nadzieję że to pomoże!

Kosta Eleftheriou
źródło
1
Listopad 2018: Wygląda na to, że FlickType i AccessibilityKit stały się prywatne lub zostały usunięte.
Chris Paveglio
3

W iOS 9 musiałem tylko:

  1. Dodaj ograniczenia z lewej i prawej strony etykiety do nadzoru.
  2. Ustaw tryb łamania linii na obcinanie w IB.
  3. Ustaw liczbę linii na 1 w IB.

Ktoś zalecił ustawienie liczby linii na 0, ale dla mnie to właśnie sprawiło, że etykieta przechodziła do wielu linii ...

Nick Yap
źródło
To załatwiło sprawę dla mnie. Właśnie wybrałem a UILabeli UITextFieldaw komórce statycznej i kliknąłem „Rozwiąż problemy z autoukładem” i „Dodaj brakujące ograniczenia”. Wszystko się zgadzało, ale funkcja Autoshrink musiała znać odległość do etykiety, dla której opcja „Dodaj brakujące wiązania” nie dodała ograniczenia.
Adrian
2

Myślę, że możesz napisać poniższy kod po przydzieleniu etykiety init

UILabel* lbl = [[UILabel alloc]initWithFrame:CGRectMake(0, 10, 280, 50)];
lbl.text = @"vbdsbfdshfisdhfidshufidhsufhdsf dhdsfhdksbf hfsdh fksdfidsf sdfhsd fhdsf sdhfh sdifsdkf ksdhfkds fhdsf dsfkdsfkjdhsfkjdhskfjhsdk fdhsf ";
[lbl setMinimumFontSize:8.0];
[lbl setNumberOfLines:0];
[lbl setFont:[UIFont systemFontOfSize:10.0]];
lbl.lineBreakMode = UILineBreakModeWordWrap;
lbl.backgroundColor = [UIColor redColor];
[lbl sizeToFit];
[self.view addSubview:lbl];

Dobrze ze mną współpracuje Użyj go

iDhaval
źródło
1
dzięki, ale to nie obliczy ani nie zmniejszy czcionki do minimum, jak rozumiem, a także dlaczego minimalna czcionka jest większa niż normalna?
Lukas
2

Dwa lata później ten problem wciąż istnieje ...

W iOS 8 / XCode 6.1 czasami stwierdzałem, że mój UILabel(utworzony w a UITableViewCell, z włączoną funkcją AutoLayout i elastycznymi ograniczeniami, dzięki czemu miał dużo miejsca) nie zmieniłby swojego rozmiaru, aby pasował do ciągu tekstowego.

Rozwiązaniem, podobnie jak w poprzednich latach, było ustawienie tekstu, a następnie zadzwonienie sizeToFit.

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    . . .
    cell.lblCreatedAt.text = [note getCreatedDateAsString];
    [cell.lblCreatedAt sizeToFit];
}

(Westchnienie.)

Mike Gledhill
źródło
1

Oto jak to zrobić Załóżmy, że następujący komunikat Etykieta to etykieta, która ma uzyskać pożądany efekt.Teraz wypróbuj te proste linie kodów:

    //SET THE WIDTH CONSTRAINTS FOR LABEL.
    CGFloat constrainedWidth = 240.0f;//YOU CAN PUT YOUR DESIRED ONE,THE MAXIMUM WIDTH OF YOUR LABEL.
 //CALCULATE THE SPACE FOR THE TEXT SPECIFIED.
    CGSize sizeOfText=[yourText sizeWithFont:yourFont constrainedToSize:CGSizeMake(constrainedWidth, CGFLOAT_MAX) lineBreakMode:UILineBreakModeWordWrap];
    UILabel *messageLabel=[[UILabel alloc] initWithFrame:CGRectMake(20,20,constrainedWidth,sizeOfText.height)];
    messageLabel.text=yourText;
    messageLabel.numberOfLines=0;//JUST TO SUPPORT MULTILINING.
Anand
źródło
hej, dziękuję za odpowiedź, ale nie muszę obliczać wysokości etykiety, mam stały rozmiar iw zależności od tego moja czcionka musi się zmniejszyć w razie potrzeby.
Lukas
1

nie działa, jeśli numberOfLines > 1 zrobiłem taki warunek-

if(lblRecLocation.text.length > 100)
    lblRecLocation.font = [UIFont fontWithName:@"app_font_name" size:10];
Vaibhav Saran
źródło
0

Spóźniłem się na imprezę, ale ponieważ miałem dodatkowy wymóg posiadania jednego słowa w wierszu, ten jeden dodatek załatwił sprawę:

label.numberOfLines = [labelString componentsSeparatedByString:@" "].count;

Apple Docs mówi:

Zwykle tekst etykiety jest rysowany czcionką określoną we właściwości czcionki. Jeśli jednak ta właściwość jest ustawiona na TAK, a tekst we właściwości text przekracza prostokąt ograniczający etykietę, odbiornik zaczyna zmniejszać rozmiar czcionki do momentu dopasowania ciągu lub osiągnięcia minimalnego rozmiaru czcionki. W systemie iOS 6 i wcześniejszych ta właściwość jest skuteczna tylko wtedy, gdy właściwość numberOfLines jest ustawiona na 1.

Ale to kłamstwo. Kłamstwo, które ci mówię! Dotyczy to wszystkich wersji iOS. W szczególności jest to prawdą, gdy używasz a UILabelwewnątrz a, UICollectionViewCelldla którego rozmiar jest określany przez ograniczenia dostosowywane dynamicznie w czasie wykonywania za pomocą układu niestandardowego (np. self.menuCollectionViewLayout.itemSize = size).

Zatem w połączeniu z adjustsFontSizeToFitWidthi minimumScaleFactor, jak wspomniano w poprzednich odpowiedziach, programowe ustawienie numberOfLinesoparte na liczbie słów rozwiązało problem automatycznego skurczu. Wykonanie czegoś podobnego na podstawie liczby słów lub nawet liczby znaków może dać „wystarczająco bliskie” rozwiązanie.

Justin Whitney
źródło
0

W Swift 4 (programowo):

let label = UILabel(frame: CGRect(x: 0, y: 0, width: 200.0, height: 200.0))
label.adjustsFontSizeToFitWidth = true
label.numberOfLines = 0

label.text = "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum."

view.addSubview(label)
Hadži Lazar Pešić
źródło
0

Swift 4, Xcode 9.4.1

Rozwiązanie, które dla mnie zadziałało: miałem etykietę w komórce widoku kolekcji i tekst etykiety był przycinany. Ustaw atrybuty jak poniżej w Storyboard

Lines = 0
LineBreak = Word Wrap
Set yourlabel's leading and trailing constraint = 0 (using Autolayout)
Naishta
źródło