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

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

有人能给我一些建议吗?


当前回答

我在iOS 7中尝试过这个功能,对我来说很有效

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self.tableView sizeToFit];
}

其他回答

基于fl034的答案。但为了萨玛林。iOS用户:

    [Register("ContentSizedTableView")]
    public class ContentSizedTableView : UITableView
    {
        public ContentSizedTableView(IntPtr handle) : base(handle)
        {
        }

        public override CGSize ContentSize { get => base.ContentSize; set { base.ContentSize = value; InvalidateIntrinsicContentSize(); } }
        public override CGSize IntrinsicContentSize
        {
            get
            {
                this.LayoutIfNeeded();
                return new CGSize(width: NoIntrinsicMetric, height: ContentSize.Height);
            }
        }
    }

如果你使用AutoLayout,有一个更好的方法:改变决定高度的约束。只需计算表内容的高度,然后找到约束并更改它。下面是一个例子(假设决定表高度的约束实际上是一个关系为“Equal”的高度约束):

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    for constraint in tableView.constraints {
        if constraint.firstItem as? UITableView == tableView {
            if constraint.firstAttribute == .height {
                constraint.constant = tableView.contentSize.height
            }
        }
    }
}

如果您不想自己跟踪表视图的内容大小变化,您可能会发现这个子类很有用。

protocol ContentFittingTableViewDelegate: UITableViewDelegate {
    func tableViewDidUpdateContentSize(_ tableView: UITableView)
}

class ContentFittingTableView: UITableView {

    override var contentSize: CGSize {
        didSet {
            if !constraints.isEmpty {
                invalidateIntrinsicContentSize()
            } else {
                sizeToFit()
            }

            if contentSize != oldValue {
                if let delegate = delegate as? ContentFittingTableViewDelegate {
                    delegate.tableViewDidUpdateContentSize(self)
                }
            }
        }
    }

    override var intrinsicContentSize: CGSize {
        return contentSize
    }

    override func sizeThatFits(_ size: CGSize) -> CGSize {
        return contentSize
    }
}

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

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