Проблема с динамической высотой для ячеек UITableView (Swift)

79

Динамический текст переменной длины вводится в метки ячеек tableview. Чтобы высота ячеек tableview менялась динамически, я реализовал viewDidLoad():

self.tableView.estimatedRowHeight = 88.0
self.tableView.rowHeight = UITableViewAutomaticDimension

Это хорошо работает для ячеек, которые еще предстоит прокрутить (как UITableViewAutomaticDimentionвызывается при прокрутке к ячейке), но не для ячеек, которые изначально отображаются на экране при загрузке таблицы с данными.

Я попытался просто перезагрузить данные (как это предлагается во многих других ресурсах):

self.tableView.reloadData()

в обоих viewDidAppear()и, viewWillAppear()и это было безрезультатно. Я потерялся ... кто-нибудь знает, как заставить xcode отображать динамическую высоту для ячеек, изначально загруженных на экран?

Пожалуйста, дайте мне знать, если есть лучший альтернативный метод.

простота
источник
Правильно ли установлены ваши ограничения по высоте для ячейки (я), я не видел никаких проблем с этим в дикой природе, используя версию Xcode 6.3. Даже есть образец проекта на github с этим рабочим. github.com/darren102/DTFAutomaticCellHeight
darren102
1
Я решил эту проблему, перекомпенсировав потенциальную высоту этикетки. Пожалуйста, посмотрите мой ответ ниже. В любом случае, если у вас есть лучшее решение, дайте мне знать!
симплексит

Ответы:

115

Попробуй это:

func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    return UITableViewAutomaticDimension
}

РЕДАКТИРОВАТЬ

func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    return UITableViewAutomaticDimension
}

Swift 4

func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
    return UITableViewAutomaticDimension
}

Swift 4.2

func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
    return UITableView.automaticDimension
}

Определите выше Оба метода.
Это решает проблему.

PS: Для этого требуются ограничения сверху и снизу.

Вот пример

iDhaval
источник
3
@bashan Работает отлично. Убедитесь, что вы установили правильные ограничения.
iDhaval 01
2
Не работает. Кажется, есть ошибка, если слово слишком длинное, но недостаточно длинное, оно не отображается должным образом. Если это несколько слов, похоже, все работает правильно.
Дживс
6
У меня это не сработало, пока я не добавил ограничение снизу. Я думаю, что в вашем ответе стоит отметить, что для этого должны быть установлены верхние и нижние ограничения.
Митч Дауни
2
Для этого необходимы нижние и верхние ограничения.
Энтони Узеф
2
Для того, чтобы это работало, необходимы нижние и верхние ограничения для «элементов ячеек»
EnasAZ
37

Использовать этот:

tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 300

и не используйте: heightForRowAtIndexPathделегировать функцию

Кроме того, в раскадровке не устанавливайте высоту метки, содержащей большой объем данных. Дайте ему top, bottom, leading, trailingограничения.

ami rt
источник
4
Ограничение снизу важно! Я пропустил это и задумался, почему невозможно вычислить высоту.
coyer
Я оставил этоheightForRowAtIndexPath
500 Ошибка сервера
@Javeed Я думаю, вы можете использовать его где угодно, например, Static cell или Dynamic Cell ..
ami rt
16

SWIFT 3

tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 160

И!!! В StoryBoard: вы ДОЛЖНЫ установить ограничения TOP и BOTTOM для своей метки. Ничего больше.

Влодзимеж Возняк
источник
11

Эта странная ошибка была решена с помощью параметров Interface Builder, поскольку другие ответы не помогли решить проблему.

Все, что я сделал, - это увеличил размер метки по умолчанию, чем потенциально может быть контент, и отразил это также на estimatedRowHeightвысоте. Раньше я устанавливал высоту строки по умолчанию в Interface Builder 88pxи отражал ее в своем контроллере следующим образом viewDidLoad():

self.tableView.rowHeight = UITableViewAutomaticDimension
self.tableView.estimatedRowHeight = 88.0

Но это не сработало. Итак, я понял, что контент никогда не станет больше, чем возможно 100px, поэтому я установил высоту ячейки по умолчанию на 108px(больше, чем потенциальное содержимое) и отразил это в контроллере следующим образом viewDidLoad():

self.tableView.rowHeight = UITableViewAutomaticDimension
self.tableView.estimatedRowHeight = 108.0

Это фактически позволило коду уменьшить начальные метки до нужного размера. Другими словами, он никогда не расширялся до большего размера, но всегда мог уменьшиться ... Кроме того, не self.tableView.reloadData()требовалось никаких дополнительных элементов viewWillAppear().

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

Не уверен, что это ошибка в Swift или Interface Builder, но работает как шарм. Попробуйте!

простота
источник
У меня такая же проблема. Я обновил свой ответ. это решило мою проблему. просто определите только этот метод и удалите все, что связано с высотой.
iDhaval
8

Установите автоматический размер для высоты строки и предполагаемой высоты строки и выполните следующие действия:

@IBOutlet weak var table: UITableView!

override func viewDidLoad() {
    super.viewDidLoad()

    // Set automatic dimensions for row height
    // Swift 4.2 onwards
    table.rowHeight = UITableView.automaticDimension
    table.estimatedRowHeight = UITableView.automaticDimension


    // Swift 4.1 and below
    table.rowHeight = UITableViewAutomaticDimension
    table.estimatedRowHeight = UITableViewAutomaticDimension

}



// UITableViewAutomaticDimension calculates height of label contents/text
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    // Swift 4.2 onwards
    return UITableView.automaticDimension

    // Swift 4.1 and below
    return UITableViewAutomaticDimension
}

Например: если у вас есть метка в UITableviewCell, тогда

  • Установить количество строк = 0 (& режим разрыва строки = обрезать хвост)
  • Установите все ограничения (сверху, снизу, справа налево) относительно контейнера супервизора / ячейки.
  • Необязательно : Установите минимальную высоту для метки, если вы хотите, чтобы минимальная вертикальная область была покрыта меткой, даже если нет данных.

Вот образец метки с динамическими ограничениями по высоте.

введите описание изображения здесь

Крунал
источник
1
Запись в ViewDidLoad (), упомянутая Круналом, была для меня решением.
SHS
7

Ячейка динамического изменения размера UITableView требовала 2 вещи

  1. Установка правильного ограничения вашего представления внутри ячейки табличного представления (в основном это включает в себя предоставление вашему представлению правильных верхних, нижних и скользящих ограничений)
  2. Вызов этих свойств TableView в viewDidLoad ()

     tableView.rowHeight = UITableViewAutomaticDimension
    
     tableView.estimatedRowHeight = 140
    

Это замечательный учебник по саморазмеру (ячейки динамического табличного представления), написанный на Swift 3.

Усама
источник
6

Для Swift 3 вы можете использовать следующее:

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    return UITableViewAutomaticDimension
}

func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
    return UITableViewAutomaticDimension
}
Ахмед Лотфи
источник
3

Для Swift 4.2

@IBOutlet weak var tableVw: UITableView!

override func viewDidLoad() {
    super.viewDidLoad()

    // Set self as tableView delegate
    tableVw.delegate = self

    tableVw.rowHeight = UITableView.automaticDimension
    tableVw.estimatedRowHeight = UITableView.automaticDimension
}

// UITableViewDelegate Method 
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {

    return UITableView.automaticDimension
}

Удачного кодирования :)

Аривен Надар
источник
2

Пытаться

override func viewWillAppear(animated: Bool) {
    self.tableView.layoutSubviews()
}

У меня была такая же проблема, и у меня она работает.

Майкелл Вилела
источник
Я попробую и дам вам знать, что происходит. Спасибо за предложение! Спустя почти год после вопроса я не нашел другого ответа, кроме своего собственного! Надеюсь на твои работы!
simplexity
не забудьте вызвать super.viewWillAppear (анимированный) перед тем, как вызывать макеты. subviews
Алан Скарпа,
2

Чтобы автоматическое изменение размера UITableViewCell работало, убедитесь, что вы вносите следующие изменения:

  • В раскадровке ваш UITableView должен содержать только динамические ячейки прототипа (он не должен использовать статические ячейки), иначе автоматическое изменение размера не будет работать.
  • В раскадровке UILabel UITableViewCell настроен для всех 4 ограничений, а именно верхних, нижних, ведущих и конечных ограничений.
  • В раскадровке количество строк UITableViewCell UILabel должно быть 0
  • В функции viewDidLoad вашего UIViewController, установленной ниже свойств UITableView:

    self.tableView.estimatedRowHeight = <minimum cell height> 
    self.tableView.rowHeight = UITableViewAutomaticDimension
    
Аншул Шарма
источник
Как реализовать то же самое, используя статические ячейки?
Javeed
Попробовав все предлагаемые здесь решения, только это (установка <minimum cell height>for estimatedRowHeight) действительно устранило мою проблему. До этого размер ячейки автоматически изменялся, но я также получал различные предупреждения об ограничениях. Теперь нет! Итак, большое спасибо, Аншул !!
RoberRM
2

Для Swift я также проверил этот ответ в iOS 9.0 и iOS 11 (Xcode 9.3)

func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    return UITableViewAutomaticDimension
}

func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
    return UITableViewAutomaticDimension
}

Здесь вам нужно добавить ограничения сверху, снизу, справа и слева.

iOS
источник
2

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

1.rowHeight = UITableView.automaticDimension, and
2.estimatedRowHeight = 100(In my case).
3.make sure label number of lines is zero.

введите описание изображения здесь

виртуальная игра
источник
2

В дополнение к тому, что сказали другие,

УСТАНАВЛИВАЙТЕ ОГРАНИЧЕНИЯ СВОЕЙ МАРКИРОВКИ ОТНОСИТЕЛЬНО НАБЛЮДЕНИЯ!

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

Затем убедитесь, что высота вашей метки больше или равна 0, а количество строк установлено на 0.

Затем ViewDidLoadдобавьте:

tableView.estimatedRowHeight = 695

tableView.rowHeight = UITableViewAutomaticDimension
Уилл сказал
источник
УСТАНАВЛИВАЙТЕ ОГРАНИЧЕНИЯ СВОЕЙ МАРКИРОВКИ ОТНОСИТЕЛЬНО НАБЛЮДЕНИЯ !: ЭКОНОМИЯ ЧАСЫ !! благодарю вас.
ACAkgul
2

Это просто, если сделать 2 вещи:

  1. установка автоматической высоты
tableView.rowHeight = UITableView.automaticDimension
  1. создание всех TableViewCell с полными ограничениями сверху вниз. Последний элемент ДОЛЖЕН определять некоторый нижний интервал до конца ячейки.

Таким образом, механизм компоновки может вычислить высоту ячейки и правильно применить значение.

Карстен
источник
1

Меня просто вдохновило ваше решение, и я попробовал другой способ.

Пожалуйста, попробуйте добавить tableView.reloadData()в viewDidAppear().

У меня это работает.

Я думаю, что за прокруткой стоит «то же самое», что и у reloadData. При прокрутке экрана это как reloadData()когда звонить viewDidAppear.

Если это сработает, ответьте, пожалуйста, на этот ответ, чтобы я был уверен в этом решении.

Кан Ченг
источник
Я попробую и обновлю, чтобы увидеть, создаст ли он такое же решение. Благодаря!
simplexity
Извини, Канг, как ни странно, это не повлияло на макет. Он оставил их как статические значения, которые они были установлены, как в Интерфейсном Разработчике, вместо того, чтобы обертывать их до нужного размера.
simplexity
1

К сожалению, я не уверен, что мне не хватало. Вышеупомянутые методы не работают для меня, чтобы получить высоту ячейки xib или позволить Layoutifneeded () или UITableView.automaticDimension выполнить расчет высоты. Я искал и пытался от 3 до 4 ночей, но не мог найти ответа. Однако некоторые ответы здесь или в другом сообщении дали мне подсказки для обходного пути. Это глупый метод, но он работает. Просто добавьте все свои ячейки в массив. А затем установите выход каждого из ваших ограничений по высоте в раскадровке xib. Наконец, добавьте их в метод heightForRowAt. Это просто, если вы не знакомы с этими API.

Swift 4.2

CustomCell.Swift

@IBOutlet weak var textViewOneHeight: NSLayoutConstraint!
@IBOutlet weak var textViewTwoHeight: NSLayoutConstraint!
@IBOutlet weak var textViewThreeHeight: NSLayoutConstraint!

@IBOutlet weak var textViewFourHeight: NSLayoutConstraint!
@IBOutlet weak var textViewFiveHeight: NSLayoutConstraint!

MyTableViewVC.Swift

.
.
var myCustomCells:[CustomCell] = []
.
.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = Bundle.main.loadNibNamed("CustomCell", owner: self, options: nil)?.first as! CustomCell

.
.
myCustomCells.append(cell)
return cell

}


override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {

   let totalHeight = myCustomCells[indexPath.row].textViewOneHeight.constant + myCustomCells[indexPath.row].textViewTwoHeight.constant +  myCustomCells[indexPath.row].textViewThreeHeight.constant + myCustomCells[indexPath.row].textViewFourHeight.constant + myCustomCells[indexPath.row].textViewFiveHeight.constant

  return totalHeight + 40 //some magic number


}
Уильям Тонг
источник
1

Я использую эти

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {

    return 100
}
gms
источник
0

Вам нужно просто установить все ограничения для TOP , BOTTOM и HEIGHT для каждого объекта в представлении / представлениях ячеек и удалить существующую среднюю позицию Y, если таковая имеется. Потому что там, где вы этого не сделали, артефакты помещаются в другие представления.

Геннадий Дмитрик
источник
3
Привет !, Этот ответ может быть хорошим, но лучше предоставить рабочий пример, который объясняет и демонстрирует ваш ответ.
ItamarG3
0

Для цели c это одно из моих хороших решений. у меня это сработало.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    cell.textLabel.text = [_nameArray objectAtIndex:indexPath.row];
    cell.textLabel.numberOfLines = 0;
    cell.textLabel.lineBreakMode = NSLineBreakByWordWrapping;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    return UITableViewAutomaticDimension;
}

Нам нужно применить эти 2 изменения.

1)cell.textLabel.numberOfLines = 0;
  cell.textLabel.lineBreakMode = NSLineBreakByWordWrapping;

2)return UITableViewAutomaticDimension;
iOS
источник
0

Первоначально у меня тоже была эта проблема, я решил свою проблему с помощью этого кода, попробуйте избежать использования self.tableView.reloadData()вместо этого кода для динамической высоты

[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationFade];
ШуджатАли
источник
0

При использовании статики UITableViewя устанавливаю все значения в UILabels, а затем вызываю tableView.reloadData().

Зандор Смит
источник
0
self.tableView.rowHeight = UITableViewAutomaticDimension
self.tableView.estimatedRowHeight = 88.0

И не забудьте добавить ограничения для метки

Винеш ТП
источник
0

Swift 5 Наслаждайтесь

tablev.rowHeight = 100
tablev.estimatedRowHeight = UITableView.automaticDimension


func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = self.tablev.dequeueReusableCell(withIdentifier: "ConferenceRoomsCell") as! ConferenceRoomsCell
    cell.lblRoomName.numberOfLines = 0
    cell.lblRoomName.lineBreakMode = .byWordWrapping
    cell.lblRoomName.text = arrNameOfRooms[indexPath.row]
    cell.lblRoomName.sizeToFit()
    return cell
}
Шакил Ахмед
источник
-1
self.Itemtableview.estimatedRowHeight = 0;
self.Itemtableview.estimatedSectionHeaderHeight = 0;
self.Itemtableview.estimatedSectionFooterHeight = 0;


[ self.Itemtableview reloadData];
self.Itemtableview.frame = CGRectMake( self.Itemtableview.frame.origin.x,  self.Itemtableview.frame.origin.y,  self.Itemtableview.frame.size.width,self.Itemtableview.contentSize.height + self.Itemtableview.contentInset.bottom + self.Itemtableview.contentInset.top);
гопи
источник
Хотя этот код может решить вопрос, в том числе объяснение того, как и почему это решает проблему, действительно поможет улучшить качество вашего сообщения и, вероятно, приведет к большему количеству голосов за. Помните, что вы отвечаете на вопрос для будущих читателей, а не только для человека, который задает его сейчас. Пожалуйста , измените свой ответ , чтобы добавить объяснения и дать указание о том , что применять ограничения и допущения.
Сурадж Рао
-3

Установите правильное ограничение и обновите методы делегата как:

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
    return UITableViewAutomaticDimension
}

Это решит проблему с динамической высотой ячейки. ЕСЛИ вам не нужно проверять ограничения.

Канджария-IOS
источник
1
Тот же код, что и ответ Ахмеда Лотфи на этой же странице ...
Эрик Айя
Хммм, я проверил
Swift
1
вы также должны
указать