可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have a non scrolling UITableView
in a UIScrollView
. I set the frame size of the UITableView
to its content size.
When I add a row to the UITableView
, I call insertRowsAtIndexPaths:withRowAnimation
: on the UITableView
. Then I call a method to resize the frame of the 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;
}
It seems though that the contentSize
hasn't been updated at this point. If I manually calculate the frame in the above method based on the number of rows and sections, then the method works properly.
My question is, how can I get the UITableView
to update its contentSize
? I suppose I could call reloadData
and that would probably do it, but it seems inefficient to reload the entire table when I'm just inserting one cell.
回答1:
You can force the UITableView to calculate the size of the content by calling layoutIfNeeded
on the UITableView.
Example for a UITableViewController subclass that should be in a container view with variable size:
- (CGSize)preferredContentSize
{
// Force the table view to calculate its height
[self.tableView layoutIfNeeded];
return self.tableView.contentSize;
}
Update 2016-07-28
This is an untested Swift example of the same thing. It should work but if it doesn't please leave a comment. There might be nicer or more idiomatic ways to do this. Unfortunately I am not very familiar with Swift.
override var preferredContentSize: CGSize {
get {
self.tableView.layoutIfNeeded()
return self.tableView.contentSize
}
set {}
}
回答2:
While I don't love KVO (Key-Value Observing), it's a fairly good way to know exactly when your table's contentSize
has changed (rather than just calling your update methods in a bunch of random places). It's rather simple to use (though somewhat cryptic and implicit). To observe changes on your table's contentSize
, do the following:
1) Become an observer of your table's contentSize
property like so:
[self.tableView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionNew context:NULL];
This is usually done in the view controller that holds the tableView
(like in viewDidLoad:
, for example).
2) Implement the KVO observing method and make the changes you need:
- (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) Remove your view controller as an observer at some logical point (I call it in dealloc
). You do this like so:
- (void)dealloc {
[self.tableView removeObserver:self forKeyPath:@"contentSize"];
}
回答3:
Try this:
- (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;
}
回答4:
Add observer (in my sample in viewDidLoad
tableView.addObserver(self, forKeyPath: "contentSize", options: .new, context: nil)
Observe value
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
}
}
}
}
Remove observer when not needed
deinit {
self.tableView.removeObserver(self, forKeyPath: "contentSize")
}
回答5:
as @Farthen suggested you should always call yourTableView.layoutIfNeeded()
to recalculate content size first.
By calling layoutIfNeeded UITableView will calculate contentSize again and then you can update the frame or constant whatever it is.
Simple two line of code will save much more efforts.
tableView.layoutIfNeeded()
tableViewHeight.constant = tableView.contentSize.height
回答6:
This worked for me, when addressing the issues of the tableview getting the right size after adding / removing rows
Using
tableView.layoutIfNeeded()
and setting
tableView.estimatedRowHeight = UITableViewAutomaticDimension
回答7:
You can change the frame of footer. I call before animated appear of footer.
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)
}