it-swarm.com.ru

Когда UITableView's contentSize устанавливается?

У меня нет прокрутки 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, и это, вероятно, сделало бы это, но кажется неэффективным перезагружать всю таблицу, когда я просто вставляю одну ячейку.

44
Darren

Вы можете заставить 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 {}
}
69
felinira

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

1) Станьте наблюдателем свойства contentSize вашей таблицы следующим образом:

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

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

2) Внедрите метод наблюдения KVO и внесите необходимые изменения:

- (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"];
}
24
Brian Sachetta

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

- (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;
}
14
rob mayoff
  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")
    }
    
6
gbk

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

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

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

tableView.layoutIfNeeded()
tableViewHeight.constant = tableView.contentSize.height
1
Anil Kukadeja

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

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
Charles Bessonnet

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

С помощью

    tableView.layoutIfNeeded()

и настройка

    tableView.estimatedRowHeight = UITableViewAutomaticDimension
0
RiceAndBytes