2014-12-28 2 views
1

Я искал весь день, но не смог заставить его работать.Как программно добавить UILabel с переменной высотой и макетом ios

У меня есть UIView с двумя надписями над другой, с левой стороны и с одной кнопкой справа. Я добавил ограничения, чтобы autolayout соответственно изменил размер. Все отлично работало, когда я установил одно ограничение для высоты UIView (и ни одно ограничение для высоты двух UILabel), но поскольку содержимое нижнего UILabel будет меняться, я удалил это ограничение и установил два ограничения для UILabel, один фиксированный для верхнего UILabel и один с отношением «больше или равно» для нижнего UILabel, а другой - для фиксации расстояния между нижними UILabel и UIView.

Похоже Автокомпоновка не способен рассчитать intrinsicContentSize низшего UILabel, потому что она никогда не увеличивает его высоту над 10px, несмотря на содержание нижней UILabel.

UIView *miView = [[UIView alloc] init]; 
UILabel *miLabel = [[UILabel alloc] init]; 
[miLabel setTranslatesAutoresizingMaskIntoConstraints:NO]; 
[miDetailsLabel setNumberOfLines:1]; 
[miDetailsLabel setText:@"Just one line."]; 
[miView addSubview:miLabel]; 
UILabel *miDetailsLabel = [[UILabel alloc] init]; 
[miDetailsLabel setTranslatesAutoresizingMaskIntoConstraints:NO]; 
[miDetailsLabel setNumberOfLines:0]; 
[miDetailsLabel setText:@"Enough text to show 3 lines on an IP4, except first of three UILabels on my test code, with no content"]; 
[miView addSubview:miDetailsLabel]; 
UIButton *miButton = [[UIButton alloc] init]; 
[miButton setTranslatesAutoresizingMaskIntoConstraints:NO]; 
[miView addSubview:miButton]; 

NSArray *constraint_inner_h = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(0)-[label]-(10)-[button(52)]-(0)-|" options:0 metrics:nil views:@{@"label":miLabel, @"button":miButton}]; 
NSArray *constraint_inner2_h = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(0)-[details]-(10)-[button]-(0)-|" options:0 metrics:nil views:@{@"details":miDetailsLabel, @"button":miButton}]; 
NSArray *constraint_label_v = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(0)-[label(18)]-(2)-[details(>=10)]-(0)-|" options:0 metrics:nil views:@{@"label":miLabel, @"details":miDetailsLabel}]; 
NSArray *constraint_button_v = [NSLayoutConstraint constraintsWithVisualFormat:@"V:[button(22)]" options:0 metrics:nil views:@{@"button":miButton}]; 
[miView addConstraint:[NSLayoutConstraint constraintWithItem:miButton attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:miView attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0.0]]; 
[miView addConstraints:constraint_inner_h]; 
[miView addConstraints:constraint_inner2_h]; 
[miView addConstraints:constraint_label_v]; 
[miView addConstraints:constraint_button_v]; 

Я поместил сокращенную версию кода.

любые идеи о том, чего я не хватает?

Благодаря

UPDATE: Спасибо Мэтту советы, я попытался это решение, чтобы установить правильное значение для preferredMawLayoutWidth:

- (void)viewDidLayoutSubviews { 
    [super viewDidLayoutSubviews]; 

    NSArray *allKeys = [dictOpcionesTickets allKeys]; 
    for (NSString *key in allKeys) { 
     NSArray *tmpArray = [dictOpcionesTickets objectForKey:key]; 
     if (![[tmpArray objectAtIndex:0] isEqual:@""]) { 
      UILabel *tmpLabel = [tmpArray objectAtIndex:3]; 
      tmpLabel.preferredMaxLayoutWidth = tmpLabel.frame.size.width; 
      NSLog(@"width: %f",tmpLabel.frame.size.width); 
     } 
    } 
    [self.view layoutIfNeeded]; 
} 

Чтобы объяснить код, как я уже сказал, я это делаю динамически, поэтому я создал словарь с массивом со ссылками на мой UILabel (среди прочих интересных сведений). Когда я запускаю код, я получаю следующий журнал (с кодом разбора 3 UILabel, первый ярлыка без содержания):

2014-12-28 20:40:42.898 myapp[5419:60b] width: 0.000000 
2014-12-28 20:40:42.912 myapp[5419:60b] width: 0.000000 
2014-12-28 20:40:43.078 myapp[5419:60b] width: 229.000000 
2014-12-28 20:40:43.080 myapp[5419:60b] width: 229.000000 
2014-12-28 20:40:43.326 myapp[5419:60b] width: 229.000000 
2014-12-28 20:40:43.327 myapp[5419:60b] width: 229.000000 

Но я все еще получаю тот же результат ... UIView все еще показывают высота равна минимальной высоте, заданной ограничениями, не отображая содержание UILabel.

ОБНОВЛЕНИЕ 2 Все еще обманывается.

Я проверил мой исходный код, но упрощена на свежий проект в Xcode 6, работает на реальном iPhone 4 с iOS7, и она работала отлично без установки preferredMaxLayoutWidth или подклассов UILabel, и даже без вызова layoutIfNeeded на родительское представление. Но когда дело доходит до реального проекта (я думаю, что он был первоначально построен в Xcode 4 или 5) не работает:

- (void)addLabelsDinamically { 
    self.labelFixed.text = @"Below this IB label goes others added dinamically..."; 

    UIButton *miBoton = [[UIButton alloc] init]; 
    miBoton.translatesAutoresizingMaskIntoConstraints = NO; 
    [miBoton setTitle:@"Hola" forState:UIControlStateNormal]; 
    [self.viewLabels addSubview:miBoton]; 
    [self.viewLabels addConstraint:[NSLayoutConstraint constraintWithItem:miBoton attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.viewLabels attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0.0]]; 
    [self.viewLabels addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[boton(22)]" options:0 metrics:nil views:@{@"boton":miBoton}]]; 
    [self.viewLabels addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:[boton(40)]" options:0 metrics:nil views:@{@"boton":miBoton}]]; 

    UILabel *miLabel = [[UILabel alloc] init]; 
    miLabel.translatesAutoresizingMaskIntoConstraints = NO; 
    miLabel.backgroundColor = [UIColor redColor]; 
    miLabel.numberOfLines = 0; 
    miLabel.text = @"ñkhnaermgñlkafmbñlkadnlñejtnhalrmvlkamnñnañorenoetñnngñsdbmnñgwn"; 
    [self.viewLabels addSubview:miLabel]; 
    [self.viewLabels addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(8)-[label]-(10)-[boton]-(8)-|" options:0 metrics:nil views:@{@"label":miLabel,@"boton":miBoton}]]; 
    [self.viewLabels addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[previous]-(8)-[label]" options:0 metrics:nil views:@{@"label":miLabel,@"previous":self.labelFixed}]]; 
    UIView *pre = miLabel; 

    miLabel = [[UILabel alloc] init]; 
    miLabel.translatesAutoresizingMaskIntoConstraints = NO; 
    miLabel.backgroundColor = [UIColor greenColor]; 
    miLabel.numberOfLines = 0; 
    miLabel.text = @"ñkhnaermgñlkafmbñlkadnlñejtnhalrmvlkamnñnañorenoetñnngñsdbmnñgwn"; 
    [self.viewLabels addSubview:miLabel]; 
    [self.viewLabels addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(8)-[label]-(10)-[boton]-(8)-|" options:0 metrics:nil views:@{@"label":miLabel,@"boton":miBoton}]]; 
    [self.viewLabels addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[previous]-(8)-[label]" options:0 metrics:nil views:@{@"label":miLabel,@"previous":pre}]]; 
} 

Ах, на одном экране я один UILabel добавлен IB, с numberOfLines набором до '0', вертикальное ограничение «больше или равно» и горизонтальное ограничение, установленное аналогичным образом (но оба ограничения, установленные на IB) ... и он отлично работает ... это заставляет меня гать !! любая помощь???

+0

Я не пробовал ваш код, но прежде чем мы будем более глубоко вовлечены в это, попробуйте установить «preferredMaxLayoutWidth» обеих меток на их фактическую ширину и посмотреть, помогает ли это. Это параметр, который указывает этикетке, как расти вертикально. – matt

+0

Хорошо, я видел это свойство в своих исследованиях, но не использовал его, потому что ширина моих меток также зависит от ширины супервизора. Что я должен надеть «preferredMaxLayoutWidth»? – raululm

+0

Ну, прежде чем мы начнем с этого, давайте начнем с кода, который действительно работает. Код, который вы указали, совершенно бессмысленен, потому что вы не присвоили своим меткам значение 'numberOfLines'. Без этого они вообще не будут переворачиваться. Итак, позвольте мне дать вам возможность пересмотреть код кода, пока на самом деле не будет что-то, что можно было бы обернуть/расти, а затем мы сможем поговорить больше. И, пожалуйста, также дайте вашим ярлыкам какой-нибудь текст, чтобы мы могли увидеть, что-то действительно происходит. – matt

ответ

3

Ну, наконец, я нашел ошибку, как я уже сказал в «ОБНОВЛЕНИИ 2», было очень странно, что она работала над добавлением через IB, но не с добавленными динамически.

Итак, я снова посмотрел на свой экран на IB и обнаружил, что у меня ограничение по высоте с «равным» отношением, когда я изменил его на «больше или равно», все это начало работать !!!! Почему я не заметил, что ограничение не было «больше или равно»? Поскольку представление с ограничением становилось все больше и больше, поскольку я добавлял в него ярлыки. Это ошибка?

Ну, подведите итоги, если кто-то найдет это полезным. «Как добавить UILabel s multi-line, который адаптируется к его контенту?»

В IOS 6 версии это была ошибка с «preferredMaxLayoutWidth», не получая ширину, когда он был «layouted», и в результате того, что программисты должны установить его с помощью кода (лучшее решение делает это динамически, пример того, что я поставил это на мой вышеупомянутый вопрос).

К счастью, iOS7 и более поздние версии, это было решено, и вы можете полагаться только на ограничения.

  1. Добавление через IB

    • Добавьте UILabel и установить «количество строк» ​​на «0» (это будет сделать UILabel использовать столько строк, сколько это необходимо).
    • Добавьте ограничения, вам нужно как минимум 3 ограничения (вывод сверху или снизу и обе стороны), четвертый будет высотой с отношением «больше или равно».
    • Убедитесь, что в контейнере представления достаточно места, а также имеет ограничение по высоте с отношением «больше или равно».
  2. Добавление с помощью кода (просто вставьте код размещен выше):

    UILabel *miLabel = [[UILabel alloc] init]; // Initialitze the UILabel 
    miLabel.translatesAutoresizingMaskIntoConstraints = NO; // Mandatory to disable old way of positioning 
    miLabel.backgroundColor = [UIColor redColor]; 
    miLabel.numberOfLines = 0; // Mandatory to allow multiline behaviour 
    miLabel.text = @"ñkhnaergñsdbmnñgwn"; // big test to test 
    [self.viewLabels addSubview:miLabel]; // Add subview to the parent view 
    [self.viewLabels addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(10)-[label]-(10)-|" options:0 metrics:nil views:@{@"label":miLabel}]]; // horizontal constraint 
    [self.viewLabels addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(10)-[label]" options:0 metrics:nil views:@{@"label":miLabel}]]; 
    UIView *pre = miLabel; 
    
    // Adding a second label to test the separation 
    miLabel = [[UILabel alloc] init]; 
    miLabel.translatesAutoresizingMaskIntoConstraints = NO; 
    miLabel.backgroundColor = [UIColor greenColor]; 
    miLabel.numberOfLines = 0; 
    miLabel.text = @"ñkhnaermgñlkafmbnoetñnngñsdbmnñgwn"; 
    [self.viewLabels addSubview:miLabel]; 
    [self.viewLabels addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(10)-[label]-(10)-|" options:0 metrics:nil views:@{@"label":miLabel,@"boton":miBoton}]]; 
    [self.viewLabels addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[previous]-(10)-[label]" options:0 metrics:nil views:@{@"label":miLabel,@"previous":pre}]]; 
    

Благодаря тем, кто пытался мне помочь !! Этот сайт поражает :)

+0

'miLabel.translatesAutoresizingMaskIntoConstraints = NO;' спас меня. Мои ограничения не будут работать, если это не задано. – user1282637

+0

Конечно, это будет работать, когда вы даете текстовую информацию, прежде чем добавлять ограничения. Но если вы добавите текст после этого, вам понадобится другой метод. – elliotrock

0

Этот ответ будет работать в программной ситуации, когда вы будете добавлять текстовую информацию динамически, и если это указано выше на UICollectionViewCell или UITableViewCell.

В таких ситуациях вам нужно будет обновить расположение и ограничение на contentView, затем установите preferedWidth:

-(void) layoutSubviews 
{ 

[super layoutSubviews]; 

[self.contentView setNeedsLayout]; 
[self.contentView layoutIfNeeded]; 

//locationName.preferredMaxLayoutWidth = locationName.frame.size.width; 
//locationDetails.preferredMaxLayoutWidth = locationDetails.frame.size.width; 

[super layoutSubviews]; 
} 

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

Вам понадобятся ограничения, добавленные в эти представления для вертикали в качестве начальной точки и UILabel нуждаются в их numberOfLines = 0

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

Смежные вопросы