我正在创建一个应用程序,它将在UILabel中有一个问题,并在UITableView中显示多项选择的答案,每行显示多项选择。问题和答案会有所不同,所以我需要这个UITableView的高度是动态的。
我想为桌子周围找一个合适的尺寸。其中,表的框架被设置为所有内容的高度。
有人能给我一些建议吗?
我正在创建一个应用程序,它将在UILabel中有一个问题,并在UITableView中显示多项选择的答案,每行显示多项选择。问题和答案会有所不同,所以我需要这个UITableView的高度是动态的。
我想为桌子周围找一个合适的尺寸。其中,表的框架被设置为所有内容的高度。
有人能给我一些建议吗?
当前回答
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
其他回答
基于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);
}
}
}
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;
}
如果您希望您的表是动态的,您将需要使用一个基于上面所详述的表内容的解决方案。如果你只是想显示一个更小的表,你可以使用容器视图并在其中嵌入一个UITableViewController——UITableView将根据容器大小调整大小。
这避免了大量的计算和对布局的调用。
如果您不想自己跟踪表视图的内容大小变化,您可能会发现这个子类很有用。
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
}
}
在表视图上为contentSize属性添加一个观察者,并相应地调整帧大小
[your_tableview addObserver:self forKeyPath:@"contentSize" options:0 context:NULL];
然后在回调中:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
CGRect frame = your_tableview.frame;
frame.size = your_tableview.contentSize;
your_tableview.frame = frame;
}
希望这对你有所帮助。