Отрегулируйте высоту UILabel для текста


112

У меня есть несколько меток, высоту которых я хочу отрегулировать в соответствии с текстом, это код, который я написал для этого сейчас

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
}

РЕДАКТИРОВАТЬ:

Проблема заключалась не в этом фрагменте кода, поэтому мое исправление заключается в самом вопросе. Это может быть полезно другим!


Взгляните на дополнения NSString UIKit, там есть методы для расчета необходимого размера без создания UILabel.
Владимир Гриценко

@VladimirGritsenko методы sizeWithFont недоступны в Swift :(
TheBurgerShot 07

Я признаю, что не являюсь экспертом по Swift, но считаю, что вы можете добавить свои собственные методы моста. Все равно стоило бы создать UILabel для расчета размера.
Владимир Гриценко

@TheBurgerShot sizeWithFontможет быть недоступен для Swift, Stringно он доступен на. NSStringВы все равно должны иметь возможность вызывать его в этом случае.
Anorak

В конце концов, ошибка была в другом и никак не связана с этим методом. Хотя это может быть полезно для других.
TheBurgerShot

Ответы:


189

Я только что поставил это на детской площадке, и у меня это работает.

Обновлено для 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
}

введите описание изображения здесь


это отлично работает и для меня на игровой площадке, ошибка, похоже, не возникает в этом конкретном месте, когда я удаляю использование этого метода, он будет скулить о некоторых println или просто о строке только с комментариями (тогда он говорит EXC_BAD_ACCESS code = 2)
TheBurgerShot

6
Он работает на игровой площадке, но изменение размеров внутри контроллера представления в XCode 6.1 не происходит
должным образом

1
Я немного не решаюсь создавать новые UILabelпо размеру; если этот метод используется внутри и layoutSubviewsимеет тенденцию к многократному вызову для каждого макета, создание дополнительного объекта может вызвать заметные задержки, особенно во время прокрутки.
Зорайр

let textRect = textString.boundingRectWithSize (CGSizeMake (320, 2000), параметры: .UsesLineFragmentOrigin, атрибуты: textAttributes, context: nil)
Сиддхарт Панчоли

Я не могу вызвать эту функцию в моем контроллере представления ... Можете ли вы подсказать мне, в чем может быть возможная причина?
Rouny

64

Если вы используете AutoLayout , вы можете настроить UILabelвысоту только с помощью пользовательского интерфейса конфигурации.

Для iOS8 или выше

  • Установите ограничение в начале / в конце для вашего UILabel
  • И измените строки UILabelс 1 на 0

введите описание изображения здесь

Для iOS7

  • Во-первых , вам нужно добавить высоту дляUILabel
  • Затем измените отношение с EqualнаGreater than or Equal

введите описание изображения здесь

  • Наконец , измените строки UILabelс 1 на 0

введите описание изображения здесь

Ваша UILabelвысота будет автоматически увеличиваться в зависимости от текста


2
И если метка находится внутри ячейки. Когда и как соответственно увеличить высоту ячеек?
oyalhi

1
@oyalhi, если ваш ярлык находится внутри ячейки tableview, см. другой мой пост stackoverflow.com/a/36277840/5381331
Phan Van Linh

3
Это отлично сработало для меня! Установите ограничения, и все будет работать правильно!
Билл Томпсон

2
не работает для меня ... слово «Label» в UILabel делает высоту = 20. После этой настройки остается 20.
gadget00

9

Я создаю это расширение, если хотите

extension UILabel {
    func setSizeFont (sizeFont: CGFloat) {
        self.font =  UIFont(name: self.font.fontName, size: sizeFont)!
        self.sizeToFit()
    }
}

8

У меня есть сильное рабочее решение.

в layoutSubviews:

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

в установщике текста:

    _title.text = newValue
    setNeedsLayout()

UPD. конечно с этими настройками UILabel:

    _title.lineBreakMode = .ByWordWrapping
    _title.numberOfLines = 0

6

Просто установив:

label.numberOfLines = 0

Ярлык автоматически регулирует свою высоту в зависимости от количества введенного текста.


27
Это не заставляет UILabel регулировать его высоту.
TheBurgerShot

6

на основе ответа Anorak, я также согласен с озабоченностью Зорайра, поэтому я добавил пару строк, чтобы удалить UILabel и вернуть только CGFloat, я не знаю, помогает ли это, поскольку исходный код не добавляет UIabel, но он не вызывает ошибки, поэтому я использую приведенный ниже код:

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
}

5

В Swift 4.1 и Xcode 9.4.1

Всего 3 шага

Шаг 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
}

Шаг 2)

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

Шаг 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)

5

Решение, предложенное Anorak в качестве вычисляемого свойства в расширении для 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
         }
    }
}

Использование:

self.brandModelLabel.frame.size.height = self.brandModelLabel.optimalHeight

Хорошее решение! Спасибо :-)
Кристина

Невозможно присвоить свойству: 'height' - свойство только для получения.
Amg91 03

4

Следуя ответу @Anorak, я добавил это расширение в String и отправил вставку в качестве параметра, потому что во многих случаях вам понадобится дополнение к вашему тексту. В любом случае, может, кому-то это пригодится.

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

label.lineBreakMode = NSLineBreakMode.ByWord Обертка этой строки помогла мне, спасибо.
Coder_A_D

3

Вот как рассчитать высоту текста в Swift. Затем вы можете получить высоту из прямоугольника и установить высоту ограничения для метки или textView и т. Д.

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)

3

просто вызовите этот метод там, где вам нужна динамическая высота для метки

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
}

3

Swift 4.0

self.messageLabel = UILabel (кадр: CGRect (x: 70, y: 60, ширина: UIScreen.main.bounds.width - 80, высота: 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, применяется ко всем абзацам, а не к словам внутри абзацев. Это свойство действует как во время обычного рисования, так и в тех случаях, когда размер шрифта должен быть уменьшен, чтобы соответствовать тексту метки в его ограничивающей рамке. По умолчанию для этого свойства установлено значение byTruncatingTail.

Эта ссылка описывает способ раскадровки сделать то же самое


2
Ответы только на коде не считаются хорошей практикой. Пожалуйста, подумайте о добавлении некоторых объяснений того, как ваш ответ отвечает на вопрос.
Яннис

2

Swift 4.0

Вместо того, чтобы рассчитывать высоту текста / метки, я просто меняю размер метки после вставки (динамического) текста.

Предполагая, что myLabel является рассматриваемым UILabel:

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

А теперь самое интересное:

var myLabelText: String = "" {
   didSet {
      myLabel.text = myLabelText
      myLabel.sizeToFit()
   }
}

2

Метод расширения Swift 4.1 для расчета высоты метки:

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
    }

}

1

Swift 5, XCode 11 способ раскадровки. Думаю, это работает для iOS 9 и выше. Например, вы хотите, чтобы метка «Описание» получала динамическую высоту, выполните следующие действия:

1) Выберите метку описания -> Перейти к инспектору атрибутов (значок карандаша), установите: Строки: 0 Разрыв строки: Перенос слов

2) Выберите свой UILabel в раскадровке и перейдите в Инспектор размеров (значок линейки). 3) Перейдите к «Приоритет сопротивления сжатию содержимого до 1 для всех других компонентов UIView (ярлыки, кнопки, просмотр изображений и т. Д.), Которые взаимодействуют с вашим ярлыком.

Например, в моем представлении вертикально расположены UIImageView, Title Label и Description Label. Я установил приоритет сопротивления сжатию содержимого равным UIImageView, а метку заголовка - 1, а метке описания - 750. Это приведет к тому, что метка описания будет занимать столько, сколько необходимо.


0

Чтобы сделать метку динамической в ​​быстром темпе, не задавайте ограничение по высоте, а в раскадровке сделайте метку, количество строк 0 также дает нижнее ограничение, и это лучший способ обработки динамической метки в соответствии с размером их содержимого.


0

Вы также можете использовать sizeThatFitsфункцию.

Например:

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.