Обновления ограничений UITableViewCell происходят только после прокрутки

#ios #swift #uitableview #ios-autolayout

#iOS #swift #uitableview #ios-автозапуск

Вопрос:

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

У меня есть пользовательская UITableViewCell, где я использую файл .xib. Я извлекаю некоторые данные при загрузке приложения, и как только они получены, я перезагружаю свой TableView. В ячейках отображается изображение и некоторые метки, и мне нужно, чтобы метки корректировали свой размер в зависимости от ширины текста для содержимого в отдельной ячейке. Скажем, у меня есть это для cellForRowAt indexPath :

 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    guard
        let cell = tableView.dequeueReusableCell(withIdentifier: MyCell.reuseIdentifier, for: indexPath) as? MyCell,
        indexPath.row < myDataArray.count
    else { return UITableViewCell() }

    let dataForCell = myDataArray[indexPath.row]
    cell.configure(with: dataForCell)
    cell.layoutIfNeeded()
    return cell
}
  

Теперь в моем MyCell.swift файле внутри configure(with:) метода я устанавливаю тексты меток, затем я также вызываю частный метод с именем setWidths() , который использует расширение, которое я добавил к UILabel , чтобы вернуть мне ширину метки после установки текста — я выполняю некоторые базовые вычисления, чтобы настроить ограничения меток так, как я хочу.

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

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

Я знаю, что это связано с идеей многократного использования ячеек и удаления из очереди, но почему первая группа ячеек размещена не по тем же правилам? Это первые ячейки, которые видит пользователь, мне нужно, чтобы они были правильными!

У кого-нибудь есть какие-либо советы для меня?

Редактировать

Я думаю, что я нацелился на проблему, однако я все еще не совсем знаю, что делать. Я должен скорректировать рассчитанную ширину метки на основе доступной с рамки ячейки. Я добавил несколько операторов печати, чтобы увидеть, изменилась ли ширина ячейки, и это так. Внутри setWidths() метода, который я добавил print(self.frame.width) , и при первой загрузке TableView он распечатывается 325.0 для каждой ячейки, но затем, когда я прокручиваю и он выделяет новые ячейки, он меняется на 414.0 (с использованием симулятора iPhone 8 Plus). Что вызывает изменение ширины рамки ячейки от первоначального макета до повторного использования ячейки?

Комментарии:

1. Почему бы вам просто не установить свои ограничения и использовать UITableViewAutomaticDimension вместо того, чтобы вычислять размер самостоятельно?

2. @LuisPerez — Я использую автоматическое измерение высоты каждой ячейки, но я не могу использовать его для ширины этих отдельных меток. У меня есть очень специфический макет, которому я должен следовать, где метки должны сжиматься в зависимости от доступного пространства для соседних меток. Это слишком сложно объяснить здесь, не просто сбивая всех с толку. Я добавил правку к своему вопросу, которая позволяет мне узнать, что происходит.

3. Думаю, теперь я понимаю, что в тот момент, когда вы вычисляете ширину своей ячейки, contentView еще не отображается, что вам нужно сделать, это изменить свой метод configure, чтобы использовать ширину, и туда вы можете отправить ширину рамки tableview, это будет что-то вроде этого: cell.configure(with: DataForCell, width: tableview.frame.width) Редактировать: после этого используйте эту ширину для вычисления размера надписей

4. @LuisPerez — Да, вы правы. Я просто попытался добавить операторы печати в viewDidLoad , а затем еще раз в cellForRowAt — по какой-то причине в viewDidLoad моем self.view.frame.width = 375.0 , но затем в cellForRowAt the self.view.frame.width = 414.0 , что делает мою математику правильной. Если вы хотите добавить ответ, я приму его. Итак, iOS просто настраивает общий размер фрейма? Почему произошла смена с 375.0 на 414.0 ? Вот чего я просто не понимаю

Ответ №1:

Проблема здесь в том, что вы вычисляете свои размеры, когда ячейка еще не отрисована, обновите свой метод configure, чтобы использовать ширину tableview, вот так cell.configure(with: DataForCell, width: tableview.frame.width) , после этого используйте эту ширину для настройки ваших размеров, и о том, почему она меняется с 375 на 414, ответ заключается в том, что вы получаете ширину обычного iphone, при отрисовке вида он меняется на plus size.

Комментарии:

1. @LuizPerez — Я также допустил глупую ошибку в своих расчетах, которую я только что осознал, на случай, если у кого-то еще есть подобная проблема. Прежде чем я рассчитал изменение ширины для одного ограничения, я изменил ширину другой метки на основе размера ее текста, и в своих расчетах я использовал otherLabel.frame.width вместо своего IBOutlet otherLabelWidthConstraint.constant . Итак, в моих расчетах использовался фрейм другой метки (который еще не изменился и был настроен на то, как его константа была расположена в файле XIB), вместо того, чтобы использовать ширину, на которую я ее изменил, но она еще не обновлялась.