Dopasuj wysokość etykiety UILabel do tekstu

112

Mam kilka etykiet, które chcę dopasować ich wysokość do tekstu, to jest kod, który teraz napisałem

func heightForView(text:String, font:UIFont, width:CGFloat) -> CGFloat{
    let label:UILabel = UILabel(frame: CGRectMake(0, 0, width, CGFloat.max))
    label.numberOfLines = 0
    label.lineBreakMode = NSLineBreakMode.ByWordWrapping
    label.font = font
    label.text = text

    label.sizeToFit()
    return label.frame.height
}

EDYTOWAĆ:

Problemu nie było w tym fragmencie kodu, więc moja poprawka tkwi w samym pytaniu. To może być nadal przydatne dla innych!

TheBurgerShot
źródło
Przyjrzyj się dodatkom NSString UIKit, są tam metody obliczania rozmiaru według potrzeb bez tworzenia UILabel.
Vladimir Gritsenko
@VladimirGritsenko metody „sizeWithFont” są niedostępne w Swift :(
TheBurgerShot
Przyznaję, że nie jestem ekspertem od Swift, ale uważam, że możesz dodać własne metody pomostowe. Nadal warto byłoby stworzyć UILabel w celu obliczenia rozmiaru.
Vladimir Gritsenko
@TheBurgerShot sizeWithFontmoże nie być dostępny dla Swift, Stringale jest dostępny na stronie. NSStringNadal powinieneś być w stanie to wywołać.
Anorak
Ostatecznie błąd był czymś innym i nie miał nic wspólnego z tą metodą. Chociaż może to być pomocne dla innych.
TheBurgerShot

Odpowiedzi:

189

Właśnie umieściłem to na placu zabaw i dla mnie działa.

Zaktualizowano dla Swift 4.0

import UIKit

 func heightForView(text:String, font:UIFont, width:CGFloat) -> CGFloat{
    let label:UILabel = UILabel(frame: CGRectMake(0, 0, width, CGFloat.greatestFiniteMagnitude))
    label.numberOfLines = 0
    label.lineBreakMode = NSLineBreakMode.byWordWrapping
    label.font = font
    label.text = text

    label.sizeToFit()
    return label.frame.height
}

let font = UIFont(name: "Helvetica", size: 20.0)

var height = heightForView("This is just a load of text", font: font, width: 100.0)

Swift 3:

func heightForView(text:String, font:UIFont, width:CGFloat) -> CGFloat{
    let label:UILabel = UILabel(frame: CGRect(x: 0, y: 0, width: width, height: CGFloat.greatestFiniteMagnitude))
    label.numberOfLines = 0
    label.lineBreakMode = NSLineBreakMode.byWordWrapping
    label.font = font
    label.text = text
    label.sizeToFit()

    return label.frame.height
}

wprowadź opis obrazu tutaj

Anorak
źródło
to działa dobrze dla mnie również na placu zabaw, błąd nie wydaje się występować w tym konkretnym miejscu, kiedy usuwam zastosowania tej metody, będzie narzekać na niektóre println lub po prostu linię z tylko komentarzami (wtedy jest napisane kod EXC_BAD_ACCESS = 2)
TheBurgerShot
6
Działa na placu zabaw, ale w kontrolerze widoku w XCode 6.1 nie
zmienia się
1
Trochę się waham, czy utworzyć nowy UILabelwedług rozmiaru; jeśli ta metoda jest używana wewnątrz, layoutSubviewsz tendencją do wielokrotnego wywoływania dla całego układu, tworzenie dodatkowego obiektu może spowodować zauważalne opóźnienia, szczególnie podczas przewijania.
Zorayr
let textRect = textString.boundingRectWithSize (CGSizeMake (320, 2000), opcje: .UsesLineFragmentOrigin, atrybuty: textAttributes, context: nil)
Siddharth Pancholi
Nie mogę wywołać tej funkcji w moim kontrolerze widoku ... Czy możesz mi zasugerować, jaki może być możliwy powód?
Rouny
64

Jeśli używasz autoukładu , możesz dostosować UILabelwysokość tylko za pomocą interfejsu użytkownika konfiguracji.

Dla iOS8 lub nowszego

  • Ustaw początek / koniec ograniczenia dla swojego UILabel
  • I zmień linie UILabelod 1 do 0

wprowadź opis obrazu tutaj

Dla iOS7

  • Najpierw musisz dodać wysokość zawieraUILabel
  • Następnie zmodyfikuj relację od EqualdoGreater than or Equal

wprowadź opis obrazu tutaj

  • Na koniec zmień linie UILabelod 1 do 0

wprowadź opis obrazu tutaj

Twój UILabelautomatycznie zwiększy wysokość w zależności od tekstu

Phan Van Linh
źródło
2
A jeśli etykieta znajduje się w komórce. Kiedy i jak odpowiednio zwiększyłbyś wysokość komórki?
oyalhi,
1
@oyalhi, jeśli Twoja etykieta znajduje się w komórce z widokiem tabeli, zobacz mój inny post stackoverflow.com/a/36277840/5381331
Phan Van Linh
3
To zadziałało idealnie dla mnie! Skonfiguruj ograniczenia i będzie działać poprawnie!
Bill Thompson,
2
nie działa dla mnie ... słowo „Etykieta” w UILabel sprawia, że ​​wysokość = 20. Po tym ustawieniu pozostaje 20.
gadget00
9

Tworzę to rozszerzenie, jeśli chcesz

extension UILabel {
    func setSizeFont (sizeFont: CGFloat) {
        self.font =  UIFont(name: self.font.fontName, size: sizeFont)!
        self.sizeToFit()
    }
}
YannSteph
źródło
8

Mam mocne rozwiązanie robocze.

w układzie

    _title.frame = CGRect(x: 0, y: 0, width: bounds.width, height: 0)
    _title.sizeToFit()
    _title.frame.size = _title.bounds.size

w narządzie tekstu:

    _title.text = newValue
    setNeedsLayout()

UPD. oczywiście z tymi ustawieniami UILabel:

    _title.lineBreakMode = .ByWordWrapping
    _title.numberOfLines = 0
dimpiax
źródło
6

Wystarczy ustawić:

label.numberOfLines = 0

Etykieta automatycznie dostosowuje swoją wysokość na podstawie ilości wprowadzonego tekstu.

Jordan Amman
źródło
27
To nie powoduje, że UILabel dostosowuje swoją wysokość.
TheBurgerShot
6

na podstawie odpowiedzi Anoraka zgadzam się również z obawą Zorayra, więc dodałem kilka wierszy, aby usunąć UILabel i zwrócić tylko CGFloat, nie wiem, czy to pomaga, ponieważ oryginalny kod nie dodaje UIabel, ale to nie zgłasza błędu, więc używam poniższego kodu:

func heightForView(text:String, font:UIFont, width:CGFloat) -> CGFloat{

    var currHeight:CGFloat!

    let label:UILabel = UILabel(frame: CGRectMake(0, 0, width, CGFloat.max))
    label.numberOfLines = 0
    label.lineBreakMode = NSLineBreakMode.ByWordWrapping
    label.font = font
    label.text = text
    label.sizeToFit()

    currHeight = label.frame.height
    label.removeFromSuperview()

    return currHeight
}
LeftyT
źródło
5

W Swift 4.1 i Xcode 9.4.1

Tylko 3 kroki

Krok 1)

//To calculate height for label based on text size and width
func heightForView(text:String, font:UIFont, width:CGFloat) -> CGFloat {
    let label:UILabel = UILabel(frame: CGRect(x: 0, y: 0, width: width, height: CGFloat.greatestFiniteMagnitude))
    label.numberOfLines = 0
    label.lineBreakMode = NSLineBreakMode.byWordWrapping
    label.font = font
    label.text = text

    label.sizeToFit()
    return label.frame.height
}

Krok 2)

//Call this function
let height = heightForView(text: "This is your text", font: UIFont.systemFont(ofSize: 17), width: 300)
print(height)//Output : 41.0

Krok 3)

//This is your label
let proNameLbl = UILabel(frame: CGRect(x: 0, y: 20, width: 300, height: height))
proNameLbl.text = "This is your text"
proNameLbl.font = UIFont.systemFont(ofSize: 17)
proNameLbl.numberOfLines = 0
proNameLbl.lineBreakMode = .byWordWrapping
infoView.addSubview(proNameLbl)
iOS
źródło
5

Rozwiązanie zaproponowane przez Anoraka jako właściwość obliczona w rozszerzeniu dla UILabel:

extension UILabel
{
var optimalHeight : CGFloat
    {
        get
        {
            let label = UILabel(frame: CGRectMake(0, 0, self.frame.width, CGFloat.max))
            label.numberOfLines = 0
            label.lineBreakMode = self.lineBreakMode
            label.font = self.font
            label.text = self.text

            label.sizeToFit()

            return label.frame.height
         }
    }
}

Stosowanie:

self.brandModelLabel.frame.size.height = self.brandModelLabel.optimalHeight
Philipp Otto
źródło
Niezłe rozwiązanie! Dziękuję :-)
Cristina,
Nie można przypisać do właściwości: „wysokość” jest właściwością tylko do pobrania.
Amg91
4

Podążając za odpowiedzią @Anorak, dodałem to rozszerzenie do String i wysłałem wstawkę jako parametr, ponieważ wiele razy będziesz potrzebować dopełnienia do tekstu. W każdym razie, może niektórym okaże się to przydatne.

extension String {

    func heightForWithFont(font: UIFont, width: CGFloat, insets: UIEdgeInsets) -> CGFloat {

        let label:UILabel = UILabel(frame: CGRectMake(0, 0, width + insets.left + insets.right, CGFloat.max))
        label.numberOfLines = 0
        label.lineBreakMode = NSLineBreakMode.ByWordWrapping
        label.font = font
        label.text = self

        label.sizeToFit()
        return label.frame.height + insets.top + insets.bottom
    }
}
Lirik
źródło
label.lineBreakMode = NSLineBreakMode.ByWordWrapping ten wiersz pomógł mi dzięki.
Coder_A_D,
3

Oto jak obliczyć wysokość tekstu w języku Swift. Następnie możesz pobrać wysokość z prostownika i ustawić wysokość ograniczenia etykiety lub TextView itp.

let font = UIFont(name: "HelveticaNeue", size: 25)!
let text = "This is some really long text just to test how it works for calculating heights in swift of string sizes. What if I add a couple lines of text?"

let textString = text as NSString

let textAttributes = [NSFontAttributeName: font]

let textRect = textString.boundingRectWithSize(CGSizeMake(320, 2000), options: .UsesLineFragmentOrigin, attributes: textAttributes, context: nil)
Collin
źródło
3

po prostu wywołaj tę metodę, gdy potrzebujesz dynamicznej wysokości dla etykiety

func getHeightforController(view: AnyObject) -> CGFloat {
    let tempView: UILabel = view as! UILabel
    var context: NSStringDrawingContext = NSStringDrawingContext()
    context.minimumScaleFactor = 0.8

    var width: CGFloat = tempView.frame.size.width

    width = ((UIScreen.mainScreen().bounds.width)/320)*width

    let size: CGSize = tempView.text!.boundingRectWithSize(CGSizeMake(width, 2000), options:NSStringDrawingOptions.UsesLineFragmentOrigin, attributes: [NSFontAttributeName: tempView.font], context: context).size as CGSize

    return size.height
}
Shubham bairagi
źródło
3

Swift 4.0

self.messageLabel = UILabel (ramka: CGRect (x: 70, y: 60, szerokość: UIScreen.main.bounds.width - 80, wysokość: 30)

messageLabel.text = message

messageLabel.lineBreakMode = .byWordWrapping //in versions below swift 3 (messageLabel.lineBreakMode = NSLineBreakMode.ByWordWrapping)    
messageLabel.numberOfLines = 0 //To write any number of lines within a label scope

messageLabel.textAlignment = .center

messageLabel.textColor = UIColor.white

messageLabel.font = messageLabel.font.withSize(12)

messageLabel.sizeToFit()

Blockquote NSParagraphStyle.LineBreakMode, stosuje się do całych akapitów, a nie do słów w akapitach.Ta właściwość obowiązuje zarówno podczas normalnego rysowania, jak iw przypadkach, gdy rozmiar czcionki musi zostać zmniejszony, aby dopasować tekst etykiety do jej obwiedni. Ta właściwość jest domyślnie ustawiona na byTruncatingTail.

Ten link opisuje sposób, w jaki storyboard robi to samo

7ur7l3
źródło
2
Odpowiedzi zawierające tylko kod nie są uważane za dobrą praktykę. Rozważ dodanie kilku wyjaśnień, w jaki sposób Twoja odpowiedź odpowiada na pytanie.
Yannis
2

Swift 4.0

Zamiast obliczać wysokość tekstu / etykiety po prostu zmieniam rozmiar etykiety po wstawieniu (dynamicznego) tekstu.

Zakładając, że myLabel to dany UILabel:

let myLabel = UILabel(frame: CGRect(x: 0, y: 0, width: *somewidth*, height: *placeholder, e.g. 20*))
myLabel.numberOfLines = 0
myLabel.lineBreakMode = .byWordWrapping
...

A teraz najlepsza część:

var myLabelText: String = "" {
   didSet {
      myLabel.text = myLabelText
      myLabel.sizeToFit()
   }
}
Patrick J.
źródło
2

Swift 4.1 metodę obliczania wysokości etykiet rozszerzenie:

extension UILabel {

    func heightForLabel(text:String, font:UIFont, width:CGFloat) -> CGFloat {
        let label:UILabel = UILabel(frame: CGRect(x: 0, y: 0, width: width, height: CGFloat.greatestFiniteMagnitude))
        label.numberOfLines = 0
        label.lineBreakMode = NSLineBreakMode.byWordWrapping
        label.font = font
        label.text = text

        label.sizeToFit()
        return label.frame.height
    }

}

źródło
1

Swift 5, XCode 11 w sposób scenorysowy. Myślę, że to działa na iOS 9 i nowszych. Chcesz na przykład etykiety „Opis”, aby uzyskać dynamiczną wysokość, wykonaj następujące czynności:

1) Wybierz etykietę opisu -> Idź do Inspektora atrybutów (ikona ołówka), ustaw: Linie: 0 Podział wiersza: Zawijanie słów

2) Wybierz swój UILabel z serii ujęć i przejdź do Inspektora rozmiaru (ikona linijki), 3) Zejdź do „Priorytet odporności na kompresję treści do 1 dla wszystkich innych komponentów UIView (etykiety, przyciski, widok obrazu itp.), Które wchodzą w interakcję z Twoją etykietą.

Na przykład mam UIImageView, etykietę tytułu i etykietę opisu pionowo w moim widoku. Ustawiam Priorytet odporności na kompresję zawartości na UIImageView i etykietę tytułu na 1, a etykietę opisu na 750. Dzięki temu etykieta opisu będzie miała taką wysokość, jaka jest potrzebna.

Doci
źródło
0

Aby szybko nadać etykietę dynamiczną, nie podawaj ograniczenia wysokości, aw scenorysie utwórz etykietę liczbę wierszy 0, która również daje ograniczenie dolne i jest to najlepszy sposób, w jaki radzę sobie z dynamiczną etykietą zgodnie z rozmiarem zawartości.

Ranjeet Raushan
źródło
0

Możesz także użyć sizeThatFitsfunkcji.

Na przykład:

label.sizeThatFits(superView.frame.size).height

Fitsyu
źródło