ios UITableView 的 contentSize 什么时候设置?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9958328/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 17:38:43  来源:igfitidea点击:

When does a UITableView's contentSize get set?

iosuitableviewuiscrollview

提问by Darren

I have a non scrolling UITableViewin a UIScrollView. I set the frame size of the UITableViewto its content size.

我有一个非滚动UITableViewUIScrollView. 我将 的框架大小设置UITableView为其内容大小。

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:

当我向 中添加一行时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;
}

It seems though that the contentSizehasn'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.

好像contentSize目前还没有更新。如果我根据行数和节数手动计算上述方法中的框架,则该方法可以正常工作。

My question is, how can I get the UITableViewto update its contentSize? I suppose I could call reloadDataand that would probably do it, but it seems inefficient to reload the entire table when I'm just inserting one cell.

我的问题是,我怎样才能UITableView更新它的contentSize?我想我可以打电话reloadData,这可能会做到,但是当我只插入一个单元格时,重新加载整个表格似乎效率低下。

回答by felinira

You can force the UITableView to calculate the size of the content by calling layoutIfNeededon the UITableView.

您可以通过调用 UITableView 强制 UITableView 计算内容的大小layoutIfNeeded

Example for a UITableViewController subclass that should be in a container view with variable size:

UITableViewController 子类的示例,该子类应该位于具有可变大小的容器视图中:

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

Update 2016-07-28This 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.

2016 年 7 月 28 日更新这是一个未经测试的 Swift 示例。它应该有效,但如果无效,请发表评论。可能有更好或更惯用的方法来做到这一点。不幸的是,我对 Swift 不是很熟悉。

override var preferredContentSize: CGSize {
    get {
        self.tableView.layoutIfNeeded()
        return self.tableView.contentSize
    }
    set {}
}

回答by Brian Sachetta

While I don't love KVO (Key-Value Observing), it's a fairly good way to know exactly when your table's contentSizehas 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:

虽然我不喜欢 KVO(键值观察),但它是准确知道表何时contentSize发生更改的一种相当不错的方法(而不是仅仅在一堆随机位置调用更新方法)。它使用起来相当简单(虽然有些神秘和隐含)。要观察表的变化contentSize,请执行以下操作:

1) Become an observer of your table's contentSizeproperty like so:

1)contentSize像这样成为表属性的观察者:

[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).

这通常在包含tableView(例如 in viewDidLoad:)的视图控制器中完成。

2) Implement the KVO observing method and make the changes you need:

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) Remove your view controller as an observer at some logical point (I call it in dealloc). You do this like so:

3) 在某个逻辑点将您的视图控制器作为观察者移除(我称之为dealloc)。你这样做:

- (void)dealloc {
    [self.tableView removeObserver:self forKeyPath:@"contentSize"];
}

回答by rob mayoff

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

回答by gbk

  1. Add observer (in my sample in viewDidLoad

    tableView.addObserver(self, forKeyPath: "contentSize", options: .new, context: nil)
    
  2. 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
                }
            }
        }
    }
    
  3. Remove observer when not needed

    deinit {
        self.tableView.removeObserver(self, forKeyPath: "contentSize")
    }
    
  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")
    }
    

回答by Anil Kukadeja

as @Farthen suggested you should always call yourTableView.layoutIfNeeded() to recalculate content size first.

正如@Farthen 建议的那样,您应该始终先调用 yourTableView.layoutIfNeeded() 来重新计算内容大小。

By calling layoutIfNeeded UITableView will calculate contentSize again and then you can update the frame or constant whatever it is.

通过调用 layoutIfNeeded UITableView 将再次计算 contentSize,然后您可以更新框架或常量,无论它是什么。

Simple two line of code will save much more efforts.

简单的两行代码会省很多力。

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

回答by Charles Bessonnet

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

回答by RiceAndBytes

This worked for me, when addressing the issues of the tableview getting the right size after adding / removing rows

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

Using

使用

    tableView.layoutIfNeeded()

and setting

和设置

    tableView.estimatedRowHeight = UITableViewAutomaticDimension