iOS: багаторядковий UILabel в автоматичній компоновці


183

У мене виникають проблеми, намагаючись домогтися дуже елементарної поведінки макета за допомогою автоматичного макета. Мій контролер подання виглядає так у IB:

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

Верхня мітка - це заголовка, я не знаю, скільки це буде рядків. Мені потрібна мітка заголовка для відображення всіх рядків тексту. Мені також потрібні дві інші мітки та невелике зображення, яке потрібно викласти прямо під заголовком, як би високим це не було. Я встановив обмеження вертикального проміжку між мітками та малим зображенням, а також обмеження на верхній інтервал між заголовком мітки та його супереглядом та обмеженням між проміжками між малим зображенням та його супереглядом. Білий UIView не має обмеження по висоті, тому він повинен розтягуватися вертикально, щоб містити його підгляди. Я встановив кількість рядків для заголовка мітки на 0.

Як я можу отримати мітку заголовка змінити розмір, щоб відповідати кількості рядків, необхідних рядку? Я розумію, що я не можу використовувати методи setFrame, оскільки я використовую функцію автоматичного макета. І мені потрібно використовувати автоматичний макет, тому що мені потрібні інші види перегляду, щоб вони знаходилися нижче заголовка мітки (звідси обмеження).

Як я можу це зробити?


3
Я також борюся з подібною проблемою. Але я все ще намагаюся отримати верхню мітку, щоб динамічно регулювати її висоту, щоб відповідати вмісту. Як ви цього домоглися?
jbandi

1
Будь ласка, розгляньте як маркування відповіді @ mwhuss як прийняту.
Джеммони

1
Чи досягли ви потрібного результату?
Анірудда

перевірте це, вам не потрібно додавати єдиний рядок коду stackoverflow.com/a/36862795/4910767
Badal Shah

Відповіді:


254

Використання -setPreferredMaxLayoutWidthна UILabelі авторозмітка має працювати з рештою.

[label setPreferredMaxLayoutWidth:200.0];

Дивіться документацію UILabel на бажанійMaxLayoutWidth .

Оновлення:

Потрібно лише встановити heightобмеження в Greater than or equal toдошці розкадрування , не потрібно встановлюватиPreferredMaxLayoutWidth.


8
Приємно, все одно це зробити в інтерфейсі?
Sjoerd Perfors

12
Також встановіть обмеження висоти в IB на велику величину або рівну ".
jowie

10
Нагадування: не забудьте встановити властивість numberOfLines.
Li Fumin

2
Так, використовуйте все, що ви хочете, щоб була максимальна ширина.
mwhuss

4
Див stackoverflow.com/a/29180323/1529675 про те , як визначити preferredMaxLayoutWidthі побачити devetc.org/code/2014/07/07/auto-layout-and-views-that-wrap.html для короткої , але інформативною рецензію, в комплекті з анімовані GIF (не моя реєстрація, я знайшов це через Google)
tboyce12

213

Розширіть кількість рядків для міток до 0, а також важливіше для висоти встановлення автоматичного макета до> = x. Авто-макет зробить все інше. Ви можете також містити інші елементи, засновані на попередньому елементі, щоб правильно розмістити їх.

автоматичний макет


Якщо цей метод не працює для вас, перегляньте відповідь Cory Imdieke про те, щоб переконатися, що наступні перегляди не забороняють автоматичній макеті змінювати розмір (можливо) багатопорядкового перегляду.
Том Говард

1
Це єдина відповідь, яка працювала для мене в осередку таблиці перегляду. Також працює з фіксованою кількістю рядків (замість 0 / необмежено)
bgolson

Для мене це не спрацювало з явним кращим набором максимальної ширини, тому переконайтесь, що для ІБ встановлено автоматичне використання при використанні цієї методики. Ура
jmc

Налаштування автоматичної максимальної ширини доступне лише в iOS8. З мого розуміння, він також регулює висоту автоматично, і, на мій досвід, вам не потрібно встановлювати обмеження висоти, щоб воно працювало. Це працювало для мене, використовуючи явну ширину.
Тоні

1
Це не спрацювало для мене. Я вважаю, що stackoverflow.com/a/13032251/1529675 - правильна відповідь.
tboyce12

48

Джерело: http://www.objc.io/issue-3/advanced-auto-layout-toolbox.html

Внутрішній розмір вмісту багаторядкового тексту

Власний розмір вмісту UILabel та NSTextField неоднозначний для багаторядкового тексту. Висота тексту залежить від ширини рядків, яку ще слід визначити при вирішенні обмежень. Для того, щоб вирішити цю проблему, обидва класи мають нове властивість під назвою preferenceMaxLayoutWidth, яке вказує максимальну ширину рядка для обчислення внутрішнього розміру вмісту.

Оскільки ми зазвичай не знаємо цієї цінності заздалегідь, нам потрібно скористатися двоступінчастим підходом, щоб отримати це право. Спочатку ми дозволяємо автоматичному розкладу виконувати свою роботу, а потім використовуємо отриманий кадр у макеті проходу, щоб оновити бажану максимальну ширину і знову сформувати макет.

- (void)layoutSubviews
{
    [super layoutSubviews];
    myLabel.preferredMaxLayoutWidth = myLabel.frame.size.width;
    [super layoutSubviews];
}

Перший виклик [super layoutSubviews] необхідний, щоб мітка отримала свій кадр, а другий виклик необхідний для оновлення макета після зміни. Якщо пропустити другий виклик, ми отримаємо помилку NSInternalInconsistencyException, оскільки ми внесли зміни в пропуск макета, які потребують оновлення обмежень, але ми не запустили макет знову.

Це також можна зробити в самому підкласі міток:

@implementation MyLabel
- (void)layoutSubviews
{
    self.preferredMaxLayoutWidth = self.frame.size.width;
    [super layoutSubviews];
}
@end

У цьому випадку нам не потрібно спочатку викликати [super layoutSubviews], тому що, коли layoutSubviews викликає, у нас вже є кадр на самій етикетці.

Щоб зробити це регулювання з рівня контролера перегляду, ми підключаємо viewDidLayoutSubviews. На цьому етапі вже встановлені кадри першого пропуску автоматичного макета, і ми можемо використовувати їх для встановлення бажаної максимальної ширини.

- (void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];
    myLabel.preferredMaxLayoutWidth = myLabel.frame.size.width;
    [self.view layoutIfNeeded];
}

Нарешті, переконайтеся, що у вас немає явного обмеження висоти на етикетці, яка має більший пріоритет, ніж пріоритет стійкості до стиснення вмісту мітки. В іншому випадку це козир обчислить висоту вмісту. Обов’язково перевірте всі обмеження, які можуть впливати на висоту етикетки.


дякую, дякую, дякую за не тільки код, але ще важливіше пояснення та приклади того, як це зробити не тільки в підкласі, але і від контролера перегляду.
djibouti33

Я намагаюся зробити це в моєму контролері перегляду, і viewDidLayoutSubviews викликається після viewWillAppear та viewDidAppear. Після того, як viewDidAppear з’явиться спалах, коли мітки будуть змінені правильно. чи є спосіб уникнути цього? чи є спосіб змінити розмір, перш ніж користувач щось побачить? в моєму випадку, мої багаторядкові етикетки в tableHeaderView, і тому я також зміна розміру висоти думка про заголовку повідомлення , грунтуючись на етикетках , використовуючи цей приклад ( stackoverflow.com/questions/20982558 / ... )
djibouti33

@ djibouti33, чи можете ви надати мінімальний зразок коду (наприклад, у форматі github repo), щоб я міг легко перевірити вашу проблему?
Антон Матосов

Дякую @Anton Наша конструкція з тих пір перейшла з UITableView на UICollectionView, і, на щастя, я не бачив такої поведінки. Якщо я зможу отримати свою історію git, щоб створити невеликий зразок проекту, я повідомлю вас.
djibouti33

Проблема для мене, оскільки я почав працювати на iOS 9 sim, але коли я протестував на iOS 8, тоді почалися проблеми. Мені потрібно встановити максимальну ширину вручну.
наз.

17

Я просто боровся з цим точним сценарієм, але з ще декількома переглядами, які потребували зміни розміру та переміщення вниз по мірі необхідності. Це ганяло мене горіхом, але я нарешті зрозумів це.

Ось ключ: Інтерфейс Builder любить додавати додаткові обмеження під час додавання та переміщення поглядів, і ви, можливо, цього не помічаєте. У моєму випадку у мене був вид на півдорозі, який мав додаткове обмеження, яке визначало розмір між ним та його наглядом, в основному фіксуючи його до цього моменту. Це означало, що нічого вище цього не може змінити розмір більше, оскільки це буде суперечити цьому обмеженню.

Простий спосіб визначити, чи це так, намагаючись змінити розмір етикетки вручну. Чи дозволяє вам IB його вирощувати? Якщо це так, чи рухаються мітки нижче так, як ви очікуєте? Перед тим, як змінити розмір, переконайтеся, що ви обидві, щоб побачити, як ваші обмеження перемістять ваші погляди:

Меню IB

Якщо подання застрягло, дотримуйтесь подань, які знаходяться під ним, і переконайтесь, що в одному з них немає місця для обмеження перегляду. Тоді просто переконайтеся, що для вашої кількості рядків параметр для мітки встановлений на 0, і він повинен піклуватися про решту.


Так, після великої кількості гри з нею я зміг отримати той ефект, який я хотів. Вам просто потрібно дуже ретельно продумати необхідні обмеження. Це не допомагає, що IB постійно кидає обмеження, яких ви не очікуєте.
Джеймс Харпе

5

Я вважаю, що вам потрібно наступне:

  • Верхня обмеження
  • Провідне обмеження (наприклад, лівий бік)
  • Зворотне обмеження (наприклад, права сторона)
  • Встановіть пріоритет обіймання вмісту, горизонтального до низького, щоб він заповнив заданий простір, якщо текст короткий.
  • Встановіть опір стиснення вмісту, горизонтального до низького, тому він замість того, щоб спробувати розширитися.
  • Встановіть кількість рядків на 0.
  • Встановіть режим розриву рядка на переведення слів.

Це повинно працювати в xcode9. Мені не доводилося нічого робити із обмеженням висоти мітки (у мене її немає): вона просто працює з поля останнім часом, коли ярлик буде обмежений (трейлінг, провідний, верхній і нижній). uikit робить все інше
Антон Тропашко,

Пріоритетом обіймання змісту була моя проблема. Дякую за те, що ви мене зрозуміли про цю властивість, а також про стійкість до стиснення. Ви допомогли мені вирішити проблему, що триває кілька годин.
Девід Гей

0

Жодне з різних рішень, знайдених у багатьох темах з цього питання, не працювало ідеально для мого випадку (x динамічні багаторядкові мітки в осередках динамічного перегляду таблиці).

Я знайшов спосіб це зробити:

Після встановлення обмежень на вашій мітці та встановлення її властивості багаторядкових у 0, складіть підклас UILabel; Я зателефонував шаблону AutoLayoutLabel:

@implementation AutoLayoutLabel

- (void)layoutSubviews{
    [self setNeedsUpdateConstraints];
    [super layoutSubviews];
    self.preferredMaxLayoutWidth = CGRectGetWidth(self.bounds);
}

@end

0

У мене є UITableViewCell, який має мітку обгортання тексту. Я працював обгортанням тексту наступним чином.

1) Встановіть обмеження UILabel наступним чином.

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

2) Встановити ні. рядків до 0.

3) До UITableViewCell додано обмеження висоти UILabel.

@IBOutlet weak var priorityLabelWidth: NSLayoutConstraint!

4) У UITableViewCell:

priorityLabel.sizeToFit()
priorityLabelWidth.constant = priorityLabel.intrinsicContentSize().width+5

-12

Один із способів зробити це ... Зі збільшенням довжини тексту спробуйте змінити (зменшити) розмір шрифту тексту мітки за допомогою

Label.adjustsFontSizeToFitWidth = YES;

1
Я хочу, щоб різні екземпляри контролера перегляду мали послідовний вигляд, тому я не хочу змінювати розмір шрифту.
Джеймс Харпе
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.