什么时候UITableView的contentSize设置好了?

时间:2012-03-31 18:01:55

标签: ios uitableview uiscrollview

我在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 个答案:

答案 0 :(得分:69)

您可以通过在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 {}
}

答案 1 :(得分:24)

虽然我不喜欢KVO(Key-Value Observing),但这是一个很好的方法来确切知道你的表library("microbenchmark") library("data.table") library("gdata") sgibb <- function(x, pat="^jel") { l <- matrix(grepl(pat, as.matrix(x)), nrow=nrow(x), ncol=ncol(x)) rowSums(l) > 0L } nrussell <- function(x, pat="jel") { apply(x, 1, function(y) any(startsWith(y, pat))) } taljlevy <- function(x, pat="^jel") { apply(x, 1, function(y) { t <- grep(pat ,y); as.logical(sum(t))}) } jeffkeller <- function(x, pat="^jel") { x[, index := apply(X = .SD, MARGIN = 1, FUN = function(y)as.logical(sum(grep("^jel", y)))), .SDcols = c("A", "B", "C")] x } set.seed(123) n <- 1e2 ch <- c("hello", "jello", "mello") p <- c(0.95, 0.03, 0.02) y <- data.table(A=sample(ch, n, replace=TRUE, prob=p), B=sample(ch, n, replace=TRUE, prob=p), C=sample(ch, n, replace=TRUE, prob=p)) microbenchmark(sgibb(y), nrussell(y), taljlevy(y), jeffkeller(y)) # Unit: microseconds # expr min lq mean median uq max neval # sgibb(y) 260.111 286.826 329.3224 303.797 356.8475 524.321 100 # nrussell(y) 1101.035 1159.175 1356.1322 1199.503 1448.1315 2566.077 100 # taljlevy(y) 1223.317 1269.526 1401.5255 1295.018 1382.8875 2570.315 100 # jeffkeller(y) 1778.812 1875.607 2088.9595 1929.091 2068.5515 3717.907 100 all.equal(sgibb(y), nrussell(y)) # [1] TRUE all.equal(sgibb(y), jeffkeller(y)$index) # [1] TRUE 何时发生了变化(而不仅仅是在一堆随机位置调用你的更新方法) 。它使用起来相当简单(尽管有点神秘和含蓄)。要观察表格contentSize的变化,请执行以下操作:

1)成为您的表contentSize属性的观察者,如下所示:

contentSize

这通常在保存[self.tableView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionNew context:NULL]; 的视图控制器中完成(例如,在tableView中)。

2)实施KVO观察方法并进行所需的更改:

viewDidLoad:

3)在某个逻辑点上以观察者的身份移除视图控制器(我在- (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 } } 中调用它)。你这样做是这样的:

dealloc

答案 2 :(得分:14)

试试这个:

- (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;
}

答案 3 :(得分:6)

  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")
    }
    

答案 4 :(得分:2)

@Farthen建议你应该总是调用yourTableView.layoutIfNeeded() 首先重新计算内容大小。

通过调用layoutIfNeeded,UITableView将再次计算contentSize,然后您可以更新帧或常量。

简单的两行代码将节省更多的工作。

tableView.layoutIfNeeded()
tableViewHeight.constant = tableView.contentSize.height

答案 5 :(得分:0)

这对我来说很有用,在解决了在添加/删除行后获得正确大小的tableview问题

使用

    tableView.layoutIfNeeded()

并设置

    tableView.estimatedRowHeight = UITableViewAutomaticDimension

答案 6 :(得分:0)

您可以更改页脚的框架。我在动画出现之前打电话。

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)
    }