我在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
并且可能会这样做,但是当我插入一个单元格时重新加载整个表似乎效率低下。
答案 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)
添加观察者(在viewDidLoad
tableView.addObserver(self, forKeyPath: "contentSize", options: .new, context: nil)
观察价值
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
}
}
}
}
不需要时删除观察者
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)
}