Когда UITableView contentSize устанавливается? - PullRequest
44 голосов
/ 31 марта 2012

У меня нет прокрутки UITableView в UIScrollView.Я устанавливаю размер кадра UITableView равным его размеру содержимого.

Когда я добавляю строку к UITableView, я вызываю insertRowsAtIndexPaths:withRowAnimation: на UITableView.Затем я вызываю метод для изменения размера фрейма UITableView:

- (void)resizeTableViewFrameHeight
{
    // Table view does not scroll, so its frame height should be equal to its contentSize height
    CGRect frame = self.tableView.frame;
    frame.size = self.tableView.contentSize;
    self.tableView.frame = frame;
}

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

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

Ответы [ 7 ]

69 голосов
/ 30 июля 2013

Вы можете заставить UITableView рассчитать размер содержимого, вызвав layoutIfNeeded для UITableView.

Пример для подкласса UITableViewController, который должен находиться в представлении контейнера с переменным размером:

- (CGSize)preferredContentSize
{
    // Force the table view to calculate its height
    [self.tableView layoutIfNeeded];
    return self.tableView.contentSize;
}

Обновление 2016-07-28 Это непроверенный Swift пример того же. Это должно работать, но если это не так, пожалуйста, оставьте комментарий. Там могут быть более хорошие и идиоматические способы сделать это. К сожалению, я не очень знаком со Swift.

override var preferredContentSize: CGSize {
    get {
        self.tableView.layoutIfNeeded()
        return self.tableView.contentSize
    }
    set {}
}
25 голосов
/ 29 декабря 2015

Хотя я не люблю KVO (Key-Value Observing), это довольно хороший способ точно узнать, когда contentSize вашей таблицы изменился (вместо того, чтобы просто вызывать ваши методы обновления в куче случайных мест). Это довольно просто в использовании (хотя и несколько загадочно и неявно). Чтобы наблюдать изменения в таблице contentSize, выполните следующие действия:

1) Станьте наблюдателем свойства contentSize вашего стола, например:

[self.tableView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionNew context:NULL];

Обычно это делается в контроллере вида, который содержит tableView (как, например, в viewDidLoad:).

2) Реализуйте метод наблюдения КВО и внесите необходимые изменения:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
    if(object == self.tableView && [keyPath isEqualToString:@"contentSize"]) {
        // perform your updates here
    }
}

3) Удалите ваш контроллер вида как наблюдателя в некоторой логической точке (я называю это в dealloc). Вы делаете это так:

- (void)dealloc {
    [self.tableView removeObserver:self forKeyPath:@"contentSize"];
}
14 голосов
/ 01 апреля 2012

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

- (void)resizeTableViewFrameHeight
{
    UITableView *tableView = self.tableView;
    CGRect frame = tableView.frame;
    frame.size.height = [tableView sizeThatFits:CGSizeMake(frame.size.width, HUGE_VALF)].height;
    tableView.frame = frame;
}
6 голосов
/ 23 марта 2017
  1. Добавить наблюдателя (в моем образце в viewDidLoad

    tableView.addObserver(self, forKeyPath: "contentSize", options: .new, context: nil)
    
  2. Наблюдайте значение

    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        if let obj = object as? UITableView {
            if obj == self.tableView && keyPath == "contentSize" {
                if let newSize = change?[NSKeyValueChangeKey.newKey] as? CGSize {
                    //do stuff here
                }
            }
        }
    }
    
  3. Удалить наблюдателя, когда он не нужен

    deinit {
        self.tableView.removeObserver(self, forKeyPath: "contentSize")
    }
    
2 голосов
/ 02 мая 2018

как @Farthen предложил, вы всегда должны вызывать yourTableView.layoutIfNeeded (), чтобы сначала пересчитать размер контента.

При вызове layoutIfNeeded UITableView снова вычислит contentSize, а затем вы можете обновить кадр или константу, какой бы она ни была.

Простые две строки кода сэкономят гораздо больше усилий.

tableView.layoutIfNeeded()
tableViewHeight.constant = tableView.contentSize.height
0 голосов
/ 14 августа 2017

Вы можете изменить кадр нижнего колонтитула.Я звоню до того, как появятся анимированные колонтитулы.

if self.newTableView.contentSize.height < self.newTableView.frame.height {
        let additionalHeight: CGFloat = self.newTableView.frame.height - self.newTableView.contentSize.height

        let tableFooterView = self.newTableView.tableFooterView!

        let x = tableFooterView.frame.origin.x
        let y = tableFooterView.frame.origin.y + additionalHeight
        let width = tableFooterView.frame.width
        let height = tableFooterView.frame.height

        tableFooterView.frame = CGRect(x: x, y: y, width: width, height: height)
    }
0 голосов
/ 22 сентября 2016

Это сработало для меня, когда я решал проблемы с отображением таблицы нужного размера после добавления / удаления строк

Использование

    tableView.layoutIfNeeded()

и установка

    tableView.estimatedRowHeight = UITableViewAutomaticDimension
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...