UILabel не поддерживает автоматическое сжатие текста под размер этикетки

119

У меня есть эта странная проблема, и я занимаюсь этим уже более 8 часов. В зависимости от ситуации мне приходится вычислять UILabelsразмер динамически,
например,
я получаю UIViewControllerсобытие и меняю UILabelsразмер. от большего к меньшему. Размер моего UILabelстановится меньше, и я получаю правильный необходимый размер, но текст в моем UILabelостается прежним, тот же размер шрифта и т. Д. Мне нужно, чтобы шрифт стал меньше, чтобы весь текст соответствовал размеру UILabel. Итак, вопрос в том, как сделать так, чтобы текст соответствовал моей этикетке autoshrinkingили что-то в этом роде?

В моем xib, UILabels autoshrinkпроверяются, а также количество строк устанавливаются в 0, а также моей строке имеет новые символы строки (\ п), и я выбрал linebreakmode к wordwrap. Может быть, кто-нибудь был в той же ситуации, что и я, и мог бы мне помочь? Я был бы очень признателен за это.

Заранее спасибо!

РЕДАКТИРОВАТЬ: UILabel минимальный размер шрифта установлен на 10

Lukas
источник
какой минимальный размер вашего шрифта для установленной вами этикетки, пожалуйста, добавьте.
AJPatel

Ответы:

160

Если вы все еще ищете лучшее решение, я думаю, это то, что вам нужно:

Логическое значение, указывающее, следует ли уменьшить размер шрифта, чтобы строка заголовка поместилась в ограничивающий прямоугольник метки (это свойство действует, только если для numberOfLinesсвойства установлено значение 1).

При установке этого свойства minimumScaleFactorНЕОБХОДИМО также установить это свойство (хорошее значение по умолчанию - 0,5).

стриж

var adjustsFontSizeToFitWidth: Bool { get set }

Objective-C

@property(nonatomic) BOOL adjustsFontSizeToFitWidth;

Логическое значение, указывающее, следует ли отрегулировать интервал между буквами, чтобы он соответствовал строке в пределах прямоугольника границ метки.

стриж

var allowsDefaultTighteningForTruncation: Bool { get set }

Objective-C

@property(nonatomic) BOOL allowsDefaultTighteningForTruncation;

Источник .

Lester
источник
18
Напомним, minimumFontSizeчто в iOS 6.0 не рекомендуется. minimumScaleFactorВместо этого используйте .
lester
14
Да, автоматическое сжатие не работает для нескольких строк в UILabel. Попытайтесь представить себе это: у вас есть текст с несколькими строками, вы хотите уменьшить его, чтобы он "соответствовал" ширине. Так следует ли сжимать весь текст, чтобы поместиться в одну строку, или слова должны оставаться в одной строке и сжиматься, чтобы соответствовать каждой ширине? Последнее является наиболее распространенным случаем, но не забывайте, что слова также размещаются в нескольких строках. Даже если автоматическое упорядочение текста отключено, вам придется столкнуться с тем, что каждая строка текста будет иметь разный размер шрифта, поскольку не все слова будут соответствовать ширине.
lester
2
Я думаю, что этот ответ с категорией здесь неплох, это может быть даже то, что вы в любом случае реализовали. Этого определенно чего-то не хватает в Apple API, или, возможно, они просто не видят, что сжатие должно быть обычным вариантом использования нескольких строк статического текста .
lester
1
ну да, это хороший момент, но в любом случае, я думаю, что если я установлю количество строк на 0, это будет своего рода четким утверждением, что может быть одна или несколько строк. И автоматическое сжатие может быть определено номерами строк, я думаю ... Но в любом случае, спасибо за разъяснение. Я думал, что делаю что-то не так. Категория - хорошая идея, я думаю, я собираюсь сделать это в другом проекте, где мне это понадобится. Ценю вашу помощь, удачи;)
Лукас
4
@lester Он должен сжиматься, чтобы весь текст был виден в количестве строк, объявленных для метки с учетом ее текущих размеров. Не нужно пытаться сделать каждую строку разного размера. Я действительно удивлен, что он не может этого понять. Поэтому, если у меня есть (потенциально) длинная строка для отображения, я могу либо иметь несколько строк, либо иметь автоматический размер, но не то и другое. Это прекрасно.
devios1
125

Вот как я получаю Autoshrinkработу UILabel (особенно для установки высоты шрифта метки в устройстве 4s из 6s Plus Storyboard) в iOS 9.2, Xcode 7.2 ...

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

  • Количество строк 0
  • Разрывы строк: клип
  • Автоусадка: минимальный масштаб шрифта 0,25
ohho
источник
15
Это 3 ингредиента, необходимые для того, чтобы этикетка действительно сжималась, мне не хватало настройки обрыва строки. Кроме того, если он находится рядом с другими метками (которые также могут автоматически уменьшаться), тогда необходимо установить приоритеты сжатия / объятия или указать явные ограничения ширины или высоты. Это должен быть принятый в настоящее время ответ.
Кори Хинтон
3
Количество строк сделало это за меня! Спасибо
Майкл
Убедитесь, что ваш ярлык имеет все ограничения, особенно ведущие и конечные.
Машхади
2
Я пробовал использовать те же параметры в Xcode8 и обнаружил, что они не работают. Пожалуйста, помогите мне, если у кого-то есть идея по этому поводу.
Ганеш
75

minimumFontSize устарела в iOS 6.

Так что используйте minimumScaleFactorвместо minmimumFontSize.

lbl.adjustsFontSizeToFitWidth = YES
lbl.minimumScaleFactor = 0.5

Swift 5

lbl.adjustsFontSizeToFitWidth = true
lbl.minimumScaleFactor = 0.5
SwiftiSwift
источник
Хорошо ответил. Решил мою проблему. Спасибо
Абдул Ясин
1
@AntonMatosov, нет!
Юлиан Онофрей
2
Да, это так (сейчас) - если вы также установите для разрывов строк значение Truncate Tail вместо
переноса
21

также мое решение - это логическая метка. adjustsFontSizeToFitWidth = YES; НО. Вы должны в Интерфейсном Разработчике переключить Перенос слов в положение « CLIP ». Затем автоматически усадите этикетки. Это очень важно.

локи-е
источник
3
Только когда я перешел с «Word Wrap» на «Clip», у меня сработало Autoshrink.
NicJ
Когда я изменил перенос слов на клип, я действительно смог изменить его размер в метке с нулевыми строками. Боже, было бы неплохо, если бы это было задокументировано.
DesignatedNerd
12

В Swift 3 (программно) мне пришлось сделать это:

let lbl = UILabel()
lbl.numberOfLines = 0
lbl.lineBreakMode = .byClipping
lbl.adjustsFontSizeToFitWidth = true
lbl.minimumScaleFactor = 0.5
lbl.font = UIFont.systemFont(ofSize: 15)
Налойко Евгений
источник
5

Вы можете написать как

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];

Вы можете рассчитать количество таких строк

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";

Надеюсь, это поможет вам :-) жду вашего ответа

Birju
источник
Итак, если установить количество строк для моей метки, текст будет автоматически уменьшаться?
Лукас
если ваш контент выходит за пределы ширины, он займет следующую строку
Бирджу
эй, я сделал, как ты предлагал, но это не работает, почему количество строк мне поможет?
Лукас
вы правы, я пробовал это бесполезно, но я нашел решение для вас, как это мой следующий ответ
Бирджу
lbl.adjustsFontSizeToFitWidth = ДА; Сработало у меня!
Разработчик
4

Ну, в конце концов, я не нашел своего ответа. И я думаю, что автоматическое сжатие не работает для нескольких строк. В итоге я использовал предложение в этой ссылке: автоматическое сжатие на UILabel с несколькими строками

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

Я не понимаю, почему это должно быть так сложно реализовать. Если я чего-то упускаю, все могут меня поправить :)

Lukas
источник
В соответствии с другими ответами здесь ключевым моментом, который не хватало, было то, что вам нужно установить перенос слов на «Обрезать». Это нелогично, но это необходимо, чтобы UILabel автоматически сжимался так, как вы хотите. Это работает с многострочным UILabel.
Дункан Бэббидж
4

Это для Swift 3 под управлением Xcode 8.2.1 (8C1002)

Лучшее решение, которое я нашел, - установить фиксированную ширину в раскадровке или IB на этикетке. Установите ограничения с помощью ограничения на поля. В вашем viewDidLoad добавьте следующие строки кода:

override func viewDidLoad() {
            super.viewDidLoad()

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

обозначить ограничения на маржу

фиксированные ограничения ширины метки для поля

инспектор атрибутов

Это сработало как шарм, и оно не выходит за рамки новой строки и не сжимает текст до ширины метки без каких-либо странных проблем и работает в Swift 3.

Роб Макелвенни
источник
4

Это отличный вопрос, потому что кажется, что к настоящему времени это будет частью встроенной UIKitфункции или связанной структуры. Вот хороший наглядный пример вопроса:

Анимация изменения размера шрифта

Нет простого способа обойти это, но это определенно возможно. Один из способов сделать это - программно попробовать разные размеры шрифтов, пока не найдете тот, который достаточно близко подходит к границам представления. Вы можете сделать это с помощью boundingRect()функции NSStringили NSAttributedString. Например:

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

Вы можете сделать бинарный поиск более эффективным, чем метод полного перебора. Если вы ищете что-то действительно надежное, есть также некоторые соображения, которые немного сложнее, включая правильный перенос слов и производительность кеширования шрифтов iOS.

Если вас интересует только отображение текста на экране простым способом, я разработал надежную реализацию в Swift, которую также использую в производственном приложении. Это UIViewподкласс с эффективным автоматическим масштабированием шрифта для любого вводимого текста, включая несколько строк. Чтобы использовать это, вы просто сделаете что-то вроде:

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

Это оно! Вы можете найти полный источник здесь: https://github.com/FlickType/AccessibilityKit

Надеюсь это поможет!

Коста Элефтериу
источник
1
Ноябрь 2018: похоже, что FlickType и AccessibilityKit стали закрытыми или были удалены.
Крис Павелио
3

В iOS 9 мне просто нужно было:

  1. Добавьте ограничения слева и справа от метки в супервизор.
  2. Установите режим разрыва строки на отсечение в IB.
  3. Установите количество строк равным 1 в IB.

Кто-то рекомендовал установить количество строк на 0, но для меня это просто заставило метку перейти на несколько строк ...

Ник Яп
источник
Это помогло мне. Я только что выбрал «a» UILabelи «a» UITextFieldв статической ячейке и нажал «Устранить проблемы с автоматическим расположением» и «Добавить отсутствующие ограничения». Все выровнялось, но Autoshrink нужно было знать расстояние до метки, для которого функция «Добавить отсутствующие ограничения» не добавляла ограничения.
Адриан
2

Я думаю, вы можете написать следующий код после выделения init Label

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];

Он отлично работает со мной Используйте его

iDhaval
источник
1
спасибо, но это не будет вычислять или уменьшать шрифт до минимально необходимого, насколько я понимаю, а также почему ваш минимальный шрифт больше обычного?
Лукас
2

Два года прошло, а эта проблема все еще актуальна ...

В iOS 8 / XCode 6.1 я иногда обнаруживал, что my UILabel(созданный в a UITableViewCell, с включенным AutoLayout и гибкими ограничениями, чтобы в нем было много места) не изменял свой размер, чтобы соответствовать текстовой строке.

Решение, как и в предыдущие годы, заключалось в том, чтобы установить текст, а затем позвонить sizeToFit.

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

(Вздох.)

Майк Гледхилл
источник
1

Вот как это сделать. Предположим, что следующая метка messageLabel - это метка, с которой вы хотите добиться желаемого эффекта. Теперь попробуйте эту простую строку кода:

    //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.
Ананд
источник
привет, спасибо за ваш ответ, но мне не нужно рассчитывать высоту метки, у меня фиксированный размер, и в зависимости от этого мой шрифт должен уменьшиться при необходимости.
Лукас
1

не работает, если numberOfLines > 1 То, что я сделал, поставило такое условие -

if(lblRecLocation.text.length > 100)
    lblRecLocation.font = [UIFont fontWithName:@"app_font_name" size:10];
Вайбхав Саран
источник
0

Я опаздываю на вечеринку, но, поскольку у меня было дополнительное требование - по одному слову в строке, это одно добавление помогло мне:

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

Документы Apple говорят:

Обычно текст метки рисуется шрифтом, который вы указываете в свойстве font. Однако, если для этого свойства установлено значение YES и текст в свойстве text превышает ограничивающий прямоугольник метки, получатель начинает уменьшать размер шрифта до тех пор, пока строка не уместится или не будет достигнут минимальный размер шрифта. В iOS 6 и более ранних версиях это свойство действует, только если для свойства numberOfLines установлено значение 1.

Но это ложь. Я говорю вам ложь! Это верно для всех версий iOS. В частности, это верно при использовании UILabelвнутри a, UICollectionViewCellразмер которого определяется ограничениями, динамически регулируемыми во время выполнения с помощью настраиваемого макета (например self.menuCollectionViewLayout.itemSize = size).

Поэтому при использовании в сочетании с adjustsFontSizeToFitWidthи minimumScaleFactor, как упоминалось в предыдущих ответах, программная настройка numberOfLinesна основе количества слов решила проблему автоматического сжатия. Выполнение чего-то подобного на основе количества слов или даже количества символов может дать "достаточно близкое" решение.

Джастин Уитни
источник
0

В Swift 4 (программно):

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)
Хаджи Лазар Пешич
источник
0

Swift 4, Xcode 9.4.1

Решение, которое сработало для меня: у меня была метка в ячейке представления коллекции , и текст метки обрезался. Установите атрибуты, как показано ниже, на раскадровке

Lines = 0
LineBreak = Word Wrap
Set yourlabel's leading and trailing constraint = 0 (using Autolayout)
Naishta
источник