Хобрук: Ваш путь к мастерству в программировании

Обернуть метку в ячейку, плохая ширина?

Я пытаюсь обернуть многострочную метку в виде таблицы статического содержимого, расширяя строку по мере необходимости в tableView:heightForRowAtIndexPath:

Будучи статической таблицей, я могу установить IBOutlets; мой ярлык _instructionLabel.

Немного упрощая (на самом деле в таблице несколько строк), это выглядит так:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    NSString *labelText = _instructionLabel.text;
    CGFloat labelWidth = _instructionLabel.frame.size.width;
    CGSize constrainToSize = (CGSize){.width = labelWidth, .height = MAXFLOAT};
    CGSize textSize = [labelText sizeWithFont:_instructionLabel.font constrainedToSize:constrainToSize lineBreakMode: _instructionLabel.lineBreakMode];
    return textSize.height + 10;
}

(Прежде чем мы продолжим: я знаю, что UILabel, вероятно, не отрисовывается в полную ширину. Я планирую выяснить, как компенсировать это позже, но здесь это не моя проблема.)

Вот проблема: labelWidth неправильно. Снимок экрана с этикеткой во время выполнения на симуляторе iPad iOS 6 (книжная ориентация) имеет ширину около 438 пикселей. Я получаю 638. (В iOS 7 я получаю 728.)

Чтобы исправить это, я добавил эти строки в viewWillAppear:

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear: animated];

    [self.tableView setNeedsLayout];
    [self.tableView layoutIfNeeded];
    [self.tableView reloadData];
}

Это вызывает второй проход через установку таблицы. Теперь labelWidth намного ближе: 482. Но это намного дальше, чем я ожидал.

Я также пытался вызвать лейбл sizeToFit, но, похоже, он опирается на те же неверные данные.

Я убедился, что размер метки в конце концов установлен правильно, поместив это в viewWillAppear:

double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
    CGRect frame = _instructionLabel.frame;
    NSLog(@"%@", NSStringFromCGRect(frame));
    // Output: {{20, 0}, {438, 30}}
});

Как я могу убедиться, что ширина метки задана правильно до последнего вызова табличного представления heightForRowAtIndexPath и перед его отрисовкой?


  • Как устанавливается _instructionLabel? Является ли это табличное представление статическим содержимым вместо динамических прототипов в IB? 18.10.2013
  • Гах. Я хотел добавить эту деталь. Я вернусь и сделаю это, но да: это статический контент. 18.10.2013
  • В моих тестах метка имеет тот же размер в -viewWillAppear:, что и в раскадровке. Изменяете ли вы текстовое содержимое этикетки перед ее измерением? Используете ли вы Auto Layout? Что может произойти, чтобы заставить макет измениться по сравнению с тем, что в раскадровке? 19.10.2013
  • Да для автоматической раскладки. Кроме этого, ничего не изменилось. Но я вполне уверен, что у меня была такая же проблема в iOS 5. Я так и не понял этого там. :) 20.10.2013

Ответы:


1

Вы играли с настройкой высоты строк в рамках этого метода?

-(void)tableView:(UITableView*)tableView willDisplayCell:(UITableViewCell*)cell forRowAtIndexPath:(NSIndexPath) {

Он вызывается после того, как некоторые из внутренних механизмов UITableView, которые мы не раскрываем, выполнили свой курс и немного «подкорректировали» ваши макеты.

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

18.10.2013
  • Единственный способ отрегулировать высоту строки — heightForRowAtIndexPath:, верно? Так что другой обратный вызов на самом деле не помогает, за исключением того, что я могу обнаружить, что что-то пошло не так, и dispatch_async reloadData. 18.10.2013
  • Я сказал «Высота строки», когда хотел сказать «Ширина метки», это плохо. Вы правильно устанавливаете высоту строки, но если вы хотите, чтобы метка имела желаемую ширину, вы должны установить _label.width в методе willDisplayCell, чтобы она выглядела так, как вам нравится. 19.10.2013
  • Некоторые из внутренних операций UITableView выполняются ПОСЛЕ вашей первоначальной настройки и расчета некоторых размеров, поэтому вам предоставляется последний шанс в методе willDisplayCell, чтобы все исправить. Это может немного раздражать, но часто вы в конечном итоге передаете одни и те же данные нескольким методам протокола UITableViewDelegate. 19.10.2013
  • Проблема в том, что высота зависит от ширины, которую вычисляет iOS. Мне нужно настроить высоту, а не ширину. Но спасибо. :) 19.10.2013
  • Это звучит иначе, чем то, на что я указывал вам. Являются ли метки, которые вы заполняете своей таблицей, достаточно статичными, чтобы вы могли предварительно вычислить высоту для всех из них и поместить результаты в словарь или массив, привязанный к классу, когда таблица впервые создается, а затем укажите метод heightForRowAtIndexPath в эта информация позже? 19.10.2013
  • Что я мог бы сделать, так это рассчитать ширину меток в каждой ориентации (L/P), на каждой ОС (6/7), на каждом устройстве (стандартное, Retina, iPad). Это звучит безумно, но если я не ошибаюсь в математике, это всего 12 комбинаций. Однако я бы предпочел, чтобы этот расчет был верным. :) 19.10.2013
  • Новые материалы

    Получение стоковых обновлений с помощью Python
    Для начинающего финансового аналитика Введение Описание: Этот проект Python создает скрипт для получения текущих обновлений акций с финансового веб-сайта Yahoo. Для этого проекта мы..

    Это все, что вам нужно знать о Kotlin в 2022 году
    Добро пожаловать! Kotlin — это язык программирования, популярность которого, кажется, растет, его действительно можно использовать для создания чего угодно, и если вы хотите узнать о Kotlin,..

    Текстовый графический интерфейс с Lanterna на Java
    Мой опыт работы с компьютерами (и текстовыми графическими пользовательскими интерфейсами) начался еще в восьмидесятых, когда я был ребенком, на дне рождения друга. Это был «новенький» Amstrad..

    Перезарядите свой мозг: умопомрачительный потенциал мозговых компьютерных интерфейсов
    Способность читать свои мысли и управлять объектами разумом долгое время были предметом человеческого любопытства, ограниченного областью научной фантастики… то есть до сих пор? С технологией,..

    Основы C# — Нулевой оператор объединения (??)
    Оператор ?? называется null-coalescing operator . Этот оператор используется для предоставления значения по умолчанию, если значение операнда в левой части оператора равно null ...

    Сравнение номеров версий в C++ с использованием синтаксического анализа строк
    Номера версий обычно используются для обозначения развития или обновлений программного обеспечения или любого другого продукта. При работе с номерами версий в C++ может быть полезно сравнить две..

    В мир искусственного интеллекта…
    ИИ — это новое топливо в современном мире. Куда бы вы ни обратились, с кем бы вы ни разговаривали — они, как правило, упоминают об ИИ хотя бы раз в ходе разговора. ИИ гудит повсюду. У каждого..