我正在创建一个应用程序,它将在UILabel中有一个问题,并在UITableView中显示多项选择的答案,每行显示多项选择。问题和答案会有所不同,所以我需要这个UITableView的高度是动态的。

我想为桌子周围找一个合适的尺寸。其中,表的框架被设置为所有内容的高度。

有人能给我一些建议吗?


当前回答

Mimo和Anooj VM的答案都很棒,但如果你有一个很大的列表,有可能帧的高度会截断你的一些单元格,这是个小问题。

所以。我稍微修改了一下答案:

dispatch_async(dispatch_get_main_queue()) {
    //This code will run in the main thread:
    CGFloat newHeight=self.tableView.contentSize.height;
    CGFloat screenHeightPermissible=(self.view.bounds.size.height-self.tableView.frame.origin.y);
    if (newHeight>screenHeightPermissible)
    {
        //so that table view remains scrollable when 'newHeight'  exceeds the screen bounds
        newHeight=screenHeightPermissible;
    }

    CGRect frame = self.tableView.frame;
    frame.size.height = newHeight;
    self.tableView.frame = frame;
}

其他回答

Swift 3, iOS 10.3

解决方案1: 只需将self.tableview.sizeToFit()放在cellForRowAt indexPath函数中。确保tableview的高度比你需要的高。 如果tableview下面没有视图,这是一个很好的解决方案。然而,如果你有,底部tableview约束将不会更新(我没有尝试修复它,因为我想出了解决方案2)

例子:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    if let cell = tableView.dequeueReusableCell(withIdentifier: "TestCell", for: indexPath) as? TestCell {
        cell.configureCell(data: testArray[indexPath.row])
        self.postsTableView.sizeToFit()
        return cell
    }

    return UITableViewCell()
}

解决方案2: 在故事板中设置tableview高度约束,并将其拖到ViewController中。如果你知道单元格的平均高度,也知道数组包含多少元素,你可以这样做:

tableViewHeightConstraint.constant = CGFloat(testArray.count) * 90.0     // Let's say 90 is the average cell height

*编辑:

在我尝试了所有的解决方案之后,每个解决方案都解决了一些问题,但不是完全解决了问题,这个答案解释并完全解决了这个问题。

Swift 5解决方案

遵循以下四个步骤:

从故事板中为tableview设置高度约束。 从故事板中拖动高度约束,并在视图控制器文件中为它创建@IBOutlet。 @IBOutlet var tableViewHeightConstraint: NSLayoutConstraint! 在覆盖函数viewDidLoad()上为contentSize属性添加一个观察者

override func viewDidLoad() {
        super.viewDidLoad()
        self.tableView.addObserver(self, forKeyPath: "contentSize", options: .new, context: nil)
 
    }

Then you can change the height for the table dynamicaly using this code: override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { if(keyPath == "contentSize"){ if let newvalue = change?[.newKey] { DispatchQueue.main.async { let newsize = newvalue as! CGSize self.tableViewHeightConstraint.constant = newsize.height } } } }

这适用于我使用自动布局,与表视图只有一个部分。

func getTableViewContentHeight(tableView: UITableView) -> CGFloat {
        tableView.bounds = CGRect(x: 0, y: 0, width: 300, height: 40)
        let rows = tableView.numberOfRows(inSection: 0)
        var height = CGFloat(0)
        for n in 0...rows - 1 {
            height = height + tableView.rectForRow(at: IndexPath(row: n, section: 0)).height
        }
        return height
    }

我在设置自动布局时调用这个函数(这里的示例使用SnapKit,但你知道的):

    let height = getTableViewContentHeight(tableView: myTableView)
    myTableView.snp.makeConstraints {
        ...
        ...
        $0.height.equalTo(height)
    }

我希望UITableView只和单元格的总和一样高;我循环遍历单元格,并积累单元格的总高度。因为表格视图的大小是CGRect。此时,我需要设置边界,以便能够尊重单元格定义的自动布局规则。我将大小设置为一个足够大的任意值。实际的大小将在稍后由自动布局系统计算。

Swift 5和4.2解决方案没有KVO, DispatchQueue,也没有自己设置约束。

这个解决方案基于古尔兹的回答。

1)创建UITableView的子类:

import UIKit

final class ContentSizedTableView: UITableView {
    override var contentSize:CGSize {
        didSet {
            invalidateIntrinsicContentSize()
        }
    }

    override var intrinsicContentSize: CGSize {
        layoutIfNeeded()
        return CGSize(width: UIView.noIntrinsicMetric, height: contentSize.height)
    }
}

2)添加一个UITableView到你的布局和设置约束的所有方面。将它的类设置为contentsizetableview。

3)你应该会看到一些错误,因为Storyboard没有考虑子类的intrinsicContentSize。通过打开大小检查器并将intrinsicContentSize重写为一个占位符值来修复此问题。这是设计时的重写。在运行时,它将在contentsizetableview类中使用重写


更新:更改了Swift 4.2的代码。如果你使用的是以前的版本,使用UIViewNoIntrinsicMetric而不是UIView.noIntrinsicMetric

如果您希望您的表是动态的,您将需要使用一个基于上面所详述的表内容的解决方案。如果你只是想显示一个更小的表,你可以使用容器视图并在其中嵌入一个UITableViewController——UITableView将根据容器大小调整大小。

这避免了大量的计算和对布局的调用。