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;
}
}
Я использую эти функции в приложении для социальных сетей, чтобы отображать разные комментарии с разной высотой ячеек! Надеюсь, поможет