Изменение размера UITableView для соответствия содержанию - PullRequest
143 голосов
/ 07 апреля 2010

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

Я бы хотел найти sizeToFit обходной путь для стола. Где фрейм таблицы установлен на высоту всего его содержимого.

Кто-нибудь может посоветовать, как мне этого добиться?

Ответы [ 16 ]

144 голосов
/ 07 апреля 2010

На самом деле я нашел ответ сам.

Я просто создаю новый CGRect для tableView.frame с height из table.contentSize.height

Это устанавливает высоту UITableView равной height его содержимого. Поскольку код изменяет пользовательский интерфейс, не забудьте запустить его в основном потоке:

dispatch_async(dispatch_get_main_queue(), ^{
        //This code will run in the main thread:
        CGRect frame = self.tableView.frame;
        frame.size.height = self.tableView.contentSize.height;
        self.tableView.frame = frame;
    });
57 голосов
/ 05 февраля 2018

Решение Swift 5 и 4.2 без KVO, DispatchQueue или установки ограничений самостоятельно.

Это решение основано на ответе Гульца .

1) Создайте подкласс UITableView:

import UIKit

final class ContentSizedTableView: UITableView {
    override var contentSize:CGSize {
        didSet {
            invalidateIntrinsicContentSize()
        }
    }

    override var intrinsicContentSize: CGSize {
        layoutIfNeeded()
        return CGSize(width: UIView.noIntrinsicMetric, height: contentSize.height)
    }
}

2) Добавьте UITableView к вашему макету и установите ограничения со всех сторон.Установите для него класс ContentSizedTableView.

3) Вы должны увидеть некоторые ошибки, потому что раскадровка не учитывает наш подкласс 'intrinsicContentSize.Исправьте это, открыв инспектор размера и переопределив intrinsicContentSize для значения заполнителя.Это переопределение для времени разработки.Во время выполнения он будет использовать переопределение в нашем ContentSizedTableView классе


Обновление: Измененный код для Swift 4.2.Если вы используете предыдущую версию, используйте UIViewNoIntrinsicMetric вместо UIView.noIntrinsicMetric

53 голосов
/ 27 сентября 2016

Быстрое решение

Выполните следующие действия:

1- Установите ограничение высоты таблицы из раскадровки.

2 - Перетащите ограничение высоты из раскадровки и создайте для него @IBOutlet в файле контроллера представления.

    @IBOutlet weak var tableHeight: NSLayoutConstraint!

3- Затем вы можете динамически изменять высоту таблицы, используя этот код:

override func viewWillLayoutSubviews() {
    super.updateViewConstraints()
    self.tableHeight?.constant = self.table.contentSize.height
}

Обновление

Если для вас вырезана последняя строка, попробуйте вызвать viewWillLayoutSubviews () в функции ячейки willDisplay:

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    self.viewWillLayoutSubviews()
}
20 голосов
/ 24 октября 2013

Я попробовал это в iOS 7, и у меня это сработало

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self.tableView sizeToFit];
}
18 голосов
/ 21 августа 2014

Добавьте наблюдателя для свойства contentSize в табличном представлении и соответственно настройте размер кадра

[your_tableview addObserver:self forKeyPath:@"contentSize" options:0 context:NULL];

затем в обратном вызове:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
    {
         CGRect frame = your_tableview.frame;
         frame.size = your_tableview.contentSize;
         your_tableview.frame = frame;
    }

Надеюсь, это поможет вам.

8 голосов
/ 17 февраля 2017

Если вы не хотите самостоятельно отслеживать изменения размера представления таблицы, этот подкласс может оказаться полезным.

protocol ContentFittingTableViewDelegate: UITableViewDelegate {
    func tableViewDidUpdateContentSize(_ tableView: UITableView)
}

class ContentFittingTableView: UITableView {

    override var contentSize: CGSize {
        didSet {
            if !constraints.isEmpty {
                invalidateIntrinsicContentSize()
            } else {
                sizeToFit()
            }

            if contentSize != oldValue {
                if let delegate = delegate as? ContentFittingTableViewDelegate {
                    delegate.tableViewDidUpdateContentSize(self)
                }
            }
        }
    }

    override var intrinsicContentSize: CGSize {
        return contentSize
    }

    override func sizeThatFits(_ size: CGSize) -> CGSize {
        return contentSize
    }
}
5 голосов
/ 02 февраля 2018

У меня было табличное представление внутри прокрутки, и я должен был вычислить высоту tableView и соответственно изменить его размер.Вот шаги, которые я предпринял:

0) добавьте UIView к вашему scrollView (возможно, будет работать без этого шага, но я сделал это, чтобы избежать возможных конфликтов) - это будет представление контейнеров для вашего табличного представления,Если вы сделаете этот шаг, то установите границы представлений прямо на те же, что и у таблицы.

1) создать подкласс UITableView:

class IntrinsicTableView: UITableView {

    override var contentSize:CGSize {
        didSet {
            self.invalidateIntrinsicContentSize()
        }
    }

    override var intrinsicContentSize: CGSize {
        self.layoutIfNeeded()
        return CGSize(width: UIViewNoIntrinsicMetric, height: contentSize.height)
    }

}

2) установить класс представления таблицы в раскадровке как IntrinsicTableView: снимок экрана: http://joxi.ru/a2XEENpsyBWq0A

3) УстановитьheightConstraint для представления вашей таблицы

4) перетащите IBoutlet вашей таблицы в ViewController

5) перетащите IBoutlet ограничения высоты вашей таблицы в ViewController

6)добавьте этот метод в свой ViewController:

override func viewWillLayoutSubviews() {
        super.updateViewConstraints()
        self.yourTableViewsHeightConstraint?.constant = self.yourTableView.intrinsicContentSize.height
    }

Надеюсь, это поможет

3 голосов
/ 13 апреля 2018

Если ваш contentSize не верен, это потому, что он основан на оценочномRowHeight (автоматически), используйте это до

tableView.estimatedRowHeight = 0;

Источник: https://forums.developer.apple.com/thread/81895

3 голосов
/ 31 августа 2017

Swift 3, iOS 10.3

Решение 1: Просто поместите self.tableview.sizeToFit() в cellForRowAt indexPath функцию. Убедитесь, что высота таблицы больше, чем вам нужно. Это хорошее решение, если у вас нет представлений под таблицей. Однако, если у вас есть, нижнее ограничение таблицы не будет обновлено (я не пытался это исправить, потому что я нашел решение 2)

Пример:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    if let cell = tableView.dequeueReusableCell(withIdentifier: "TestCell", for: indexPath) as? TestCell {
        cell.configureCell(data: testArray[indexPath.row])
        self.postsTableView.sizeToFit()
        return cell
    }

    return UITableViewCell()
}

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

tableViewHeightConstraint.constant = CGFloat(testArray.count) * 90.0     // Let's say 90 is the average cell height

* EDIT:

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

1 голос
/ 09 мая 2017

Существует гораздо лучший способ сделать это, если вы используете AutoLayout: измените ограничение, которое определяет высоту. Просто рассчитайте высоту содержимого вашей таблицы, затем найдите ограничение и измените его. Вот пример (при условии, что ограничение, которое определяет высоту вашей таблицы, на самом деле является ограничением высоты с отношением «Равный»):

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    for constraint in tableView.constraints {
        if constraint.firstItem as? UITableView == tableView {
            if constraint.firstAttribute == .height {
                constraint.constant = tableView.contentSize.height
            }
        }
    }
}
...