Программное размещение UILabels, добавленное динамически внутри UIView с автомакетом

У меня есть массив элементов, которые будут отображаться внутри моего UITableViewCell. Каждый из этих элементов будет динамически отображаться с помощью UILabel. Я использую autolayout для настройки макета представлений.

Вот как я размещаю свой tableViewCell:

+------------------------------------------------+
| [cellView]                                     |
| +---------------------------------------------+|
| |[otherView] <- fixed height                  ||
| | +------------------------------------------+||
| | |[UILabel]                                 |||
| | +------------------------------------------+||
| +---------------------------------------------+|
| +---------------------------------------------+|
| |[itemView]                                   ||
| | +---------------------------+ +------------+||
| | |[itemLabel]                |-|[priceLabel]|||
| | +---------------------------+ +------------+||
| | +---------------------------+ +------------+||
| | |[itemLabel]                |-|[priceLabel]|||
| | +---------------------------+ +------------+||                                            
| |                                             ||
| |     --Add the next UILabels dynamically--   ||
| +---------------------------------------------+|
+------------------------------------------------+   

Для ясности

  • otherView: внутри него 2 UILabel. Фиксированная высота.
  • itemView: есть неизвестное количество itemLabel и priceLabel внутри. Изменяет размер высоты на основе числа items.
  • Каждое из ограничений представлений устанавливается с помощью раскадровки, кроме itemLabel и priceLabel.

Внутри моего cellForRowAtIndexPath я установил ограничения itemLabel и priceLabel, используя constraintsWithVisualFormat:

for (NSDictionary *item in items) {
    UILabel *itemLabel = [[UILabel alloc] init];
    itemLabel.translatesAutoresizingMaskIntoConstraints = NO;
    itemLabel.font = [UIFont systemFontOfSize:14.0f];
    itemLabel.backgroundColor = [UIColor yellowColor];
    itemLabel.text = [item valueForKey:@"item_name"];
    [cell.itemView addSubview:itemLabel];
    
    UILabel *priceLabel = [[UILabel alloc] init];
    priceLabel.translatesAutoresizingMaskIntoConstraints = NO;
    priceLabel.font = [UIFont systemFontOfSize:14.0f];
    priceLabel.textAlignment = NSTextAlignmentRight;
    priceLabel.backgroundColor = [UIColor greenColor];
    priceLabel.text = [NSString stringWithFormat:@"RM %@", [item valueForKey:@"price"]];
    [cell.itemView addSubview:priceLabel];
    
    NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings(cell.itemView, itemLabel, priceLabel);
    [cell.itemView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[itemLabel]-5-[priceLabel(70)]|"
                                                                         options:0
                                                                         metrics:nil
                                                                           views:viewsDictionary]];
    [cell.itemView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[itemLabel]|"
                                                                          options:0
                                                                          metrics:nil
                                                                            views:viewsDictionary]];
    [cell.itemView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[priceLabel]|"
                                                                          options:0
                                                                          metrics:nil
                                                                            views:viewsDictionary]];


}

Конечный результат, как показано ниже. Единственная проблема заключается в том, что созданные itemLabel и priceLabel перекрывают друг друга, а не выравниваются сверху вниз.

Results:

Конечные результаты

View debug:

Просмотреть отладку

Как правильно установить ограничения, чтобы itemLabel и priceLabel хорошо выровнялись сверху вниз, а размер itemView изменялся в зависимости от количества элементов внутри него?


person Faiz Mokhtar    schedule 27.04.2015    source источник


Ответы (1)


У вас недостаточно ограничений. Проблема в том, что вы не устанавливаете ограничения между, скажем, одним itemLabel и предыдущим itemLabel. Когда вы зацикливаетесь, вам нужно отслеживать метку предыдущего элемента, чтобы вы могли отстоять от нее от этого.

Другими словами: техника, которую вы ищете, состоит в том, что есть три случая:

  • первая метка. Он прикреплен к тому, что находится над ним (возможно, к верхней части супервизора).

  • Все остальные метки элементов, кроме последней. Каждая прикреплена к предыдущей метке.

  • последняя метка. Он прикрепляется к предыдущей метке и внизу, что придает ячейке ее высоту.

По невероятному совпадению у меня действительно есть код, иллюстрирующий этот принцип; ситуация, очевидно, не на 100% идентична вашей, но принцип именно такой, которому вы хотите следовать:

UILabel* previousLab = nil;
for (int i=0; i<30; i++) {
    UILabel* lab = [UILabel new];
    // lab.backgroundColor = [UIColor redColor];
    lab.translatesAutoresizingMaskIntoConstraints = NO;
    lab.text = [NSString stringWithFormat:@"This is label %d", i+1];
    [sv addSubview:lab];
    [sv addConstraints:
     [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(10)-[lab]"
                                             options:0 metrics:nil
                                               views:@{@"lab":lab}]];
    if (!previousLab) { // first one, pin to top
        [sv addConstraints:
         [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(10)-[lab]"
                                                 options:0 metrics:nil
                                                   views:@{@"lab":lab}]];
    } else { // all others, pin to previous
        [sv addConstraints:
         [NSLayoutConstraint
          constraintsWithVisualFormat:@"V:[prev]-(10)-[lab]"
          options:0 metrics:nil
          views:@{@"lab":lab, @"prev":previousLab}]];
    }
    previousLab = lab;
}

// last one, pin to bottom, this dictates content size height
[sv addConstraints:
 [NSLayoutConstraint constraintsWithVisualFormat:@"V:[lab]-(10)-|"
                                         options:0 metrics:nil
                                           views:@{@"lab":previousLab}]];
person matt    schedule 27.04.2015
comment
Кстати, я не на 100% уверен, что это хорошее использование табличного представления. Но это другой вопрос! :) - person matt; 27.04.2015
comment
Спасибо @matt, я попробую. - person Faiz Mokhtar; 27.04.2015
comment
Хорошо, я попробовал три случая, и это работает. Теперь мне нужно только изменить размер супервизора и ячейки. Спасибо @мат. :) - person Faiz Mokhtar; 27.04.2015
comment
@faizmokhtar вместо того, чтобы размещать несколько меток друг над другом внутри ячейки, не лучше ли было бы, чтобы каждая метка находилась внутри своей собственной ячейки? Каждый заказ может быть разделом (номер заказа печатается в заголовке раздела), поэтому вашему табличному представлению не нужно будет загружать все данные, и у вас будет больше гибкости при настройке таблицы позже. - person usergio2; 27.04.2015
comment
@usergio2 Да, это то, что я имел в виду в своем предыдущем комментарии, когда сказал, что это не похоже на хорошее использование табличного представления. Тем не менее, проблема, как указано, заслуживает внимания, даже если OP не может создать реальный интерфейс. - person matt; 27.04.2015
comment
@usergio2 usergio2 Да, вместо этого я приму ваше предложение. Спасибо :) - person Faiz Mokhtar; 28.04.2015