iOS Autolayout: как перемещать представления, когда текст метки становится длиннее

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

.________________________________________.
|                                        |
|  [firstlabel] [img] [secondlabel]    > |
|________________________________________|

Однако если метки становятся длиннее, изображение и вторая метка должны переместиться на вторую строку:

.________________________________________.
|                                        |
|  [firstveryverylonglabel]            > |
|   [img] [secondverylonglabel]          |
|________________________________________|

Как бы я сделал это с autolayout?

Первый ярлык прост - просто добавьте ограничения слева и сверху. Метки всегда имеют высоту только одну строку и обрезаются посередине, если текст становится слишком длинным.

Изображение всегда должно быть перед второй меткой (пространство по умолчанию) по горизонтали, а обе - по центру по вертикали. Размер изображения должен масштабироваться с учетом размера шрифта динамического текста (предпочитаемый метод FontForTextStyle:UIFontTextStyleBody), так что если пользователь выбирает большой текст, изображение также становится больше.

Высота клетки, конечно, должна увеличиваться, если нужны две линии.

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

Мое приложение должно работать под iOS 7 и более поздними версиями - для iOS 6 не требуется. Поэтому я должен вычислить высоту в tableview:heightForCellAtIndexPath: и использовать скрытую ячейку, чтобы позволить Autolayout творить там свое волшебство.

2 ответа

Решение

I ended with setting constraints in code. I embedded the labels and the image in another view, then implemented -updateConstraints for the cell and the view.

В -tableView:heightForRowAtIndexPath:Я сначала позволил Autolayout сделать первый проход в статической скрытой ячейке (только для измерения), чтобы настроить contentView, вызвав layoutIfNeededзатем принудительно обновите ограничения, вызвав setNeedsUpdateConstraints с последующим updateConstraintsIfNeededи, наконец, измерить высоту ячейки с systemLayoutSizeFittingSize:UILayoutFittingCompressedSize,

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

  [self removeConstraints];
  [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:
        @"V:|-margin-[first]-margin-|"
    options:0 metrics:metrics views:views]];
  [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:
        @"H:|-margin-[first]-[image]-[second]-margin-|"
    options:NSLayoutFormatAlignAllCenterY metrics:metrics views:views]];

Тогда я звоню systemLayoutSizeFittingSize:UILayoutFittingCompressedSize в представлении и сравните ширину с максимально возможным пространством внутри contentView, учитывая его фиксированную горизонтальную начальную позицию. Если он слишком широкий, мне нужно установить ограничение в две строки:

  [self removeConstraints];
  [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:
        @"V:|-margin-[first]-[second]-margin-|"
    options:0 metrics:metrics views:views]];
  [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:
        @"H:|-margin-[first]-margin-|"
    options:0 metrics:metrics views:views]];
  [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:
        @"H:|-margin-[image]-[second]-margin-|"
    options:NSLayoutFormatAlignAllCenterY metrics:metrics views:views]];

В камере updateConstraints метод, я просто называю setNeedsUpdateConstraints на вид, чтобы убедиться, что вид пересчитывается после изменения размера ячейки (например, при повороте портрета<=>пейзаж). И это все.

Для динамического размера ваших ячеек с текстом я рекомендую вам использовать UITextView вместо UILabel,

Вот функция, которая будет определять размер вашего UITextView в зависимости от введенного текста и шрифта.

-(CGSize)frameForText:(NSString*)text sizeWithFont:(UIFont*)font constrainedToSize:(CGSize)size{

    NSDictionary *attributesDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
                                          font, NSFontAttributeName,
                                          nil];
    CGRect frame = [text boundingRectWithSize:size
                                      options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading)
                                   attributes:attributesDictionary
                                      context:nil];

    // This contains both height and width, but we really care about height.
    return frame.size;
}

Теперь вам нужно вернуть высоту вашей ячейки в зависимости от этой функции:

// This is the method that determines the height of each cell.
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {


    // I am using a helper method here to get the text at a given cell.
    NSString *text = [self getTextAtIndex:indexPath];

    // Getting the height needed by the dynamic text view.
    CGSize size = [self frameForText:text sizeWithFont:nil constrainedToSize:CGSizeMake(yourTextView.height, CGFLOAT_MAX)];

    //If the height of textView is larger than your default textView height, 
    //then you need to to give it your default height of your cell + extra 
    //size for your text
    if (size.height>=defaultsize)
    {
        return size.height + defaultCellHeight;
    }
    else
    {
        return defaultCellHeight;
    }

}

Я использую эти функции в приложении для социальных сетей, чтобы отображать разные комментарии с разной высотой ячеек! Надеюсь, поможет

Другие вопросы по тегам