调整UITableView的大小以适应内容

MiM*_*iMo 151 objective-c uitableview ios sizetofit

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

我想找到一个sizeToFit解决方案.表格的框架设置为其所有内容的高度.

任何人都可以建议我如何实现这一目标?

MiM*_*iMo 150

其实我自己找到了答案.

我只是创建一个新CGRecttableView.frameheighttable.contentSize.height

这台的高度UITableViewheight它的内容.由于代码修改了UI,因此不要忘记在主线程中运行它:

dispatch_async(dispatch_get_main_queue(), ^{
        //This code will run in the main thread:
        CGRect frame = self.tableView.frame;
        frame.size.height = self.tableView.contentSize.height;
        self.tableView.frame = frame;
    });
Run Code Online (Sandbox Code Playgroud)

  • 放置此代码的最佳位置在哪里?我在viewDidLoad中尝试过它并且它不起作用,因为tableview委托方法尚未解雇.哪种委托方法最好? (23认同)
  • 将此代码放在viewWillLayoutSubViews中 (15认同)
  • 我这样做是viewDidAppear,它似乎有效.请注意,tableview可能比其内容高一些,因为它为节头和页脚留下了一些空间 (4认同)
  • 这种方法可能会遇到问题.如果你有一个大的列表,框架的高度可能会切断你的一些细胞.如果您启用了弹跳并且滚动到底部以查看某些单元格从视图中弹出,您可以看到这种情况发生. (3认同)
  • 我发现在所有初始tableView cellForRowAtIndexPath调用完成后,viewDidAppear是放置您想要发生的事情的好地方 (2认同)

fl0*_*034 79

没有KVO,DispatchQueue或自己设置约束的Swift 4.2解决方案.

该解决方案基于Gulz的答案.

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)
    }
}
Run Code Online (Sandbox Code Playgroud)

2)添加UITableView到您的布局并在所有方面设置约束.将其类设置为ContentSizedTableView.

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


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

  • 很好的答案,它对我有用,谢谢。不过有一件事 - 在我的情况下,我需要在故事板中将 `tableView` 的类更改为 `IntrinsicTableView`。我不需要将我的表格视图嵌入另一个`UIView`。 (2认同)
  • **Swift 4** 这对我来说很好用``tableView.sizeToFit()`` (2认同)
  • 太棒了,谢谢!最后匹配父级并包装表视图的内容...... (2认同)

Mus*_*tri 64

快速解决方案

跟着这些步骤:

1-从故事板中设置表的高度约束.

2-从故事板拖动高度约束,并在视图控制器文件中为其创建@IBOutlet.

    @IBOutlet weak var tableHeight: NSLayoutConstraint!
Run Code Online (Sandbox Code Playgroud)

3-然后,您可以使用以下代码动态更改表格的高度:

override func viewWillLayoutSubviews() {
    super.updateViewConstraints()
    self.tableHeight?.constant = self.table.contentSize.height
}
Run Code Online (Sandbox Code Playgroud)

更新

如果为您剪切了最后一行,请尝试在willDisplay单元格函数中调用viewWillLayoutSubviews():

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    self.viewWillLayoutSubviews()
}
Run Code Online (Sandbox Code Playgroud)

  • 这个解决方案总是切断Xcode 8.3的最后一行. (4认同)
  • 我必须将其放入 cellForRowAtIndexPath: 方法中。如果我将其放入 viewWillLayoutSubviews 方法中,计算出的 contentSize 高度将基于估计高度,而不是实际内容高度。 (3认同)

Ale*_*xey 20

我在iOS 7中试过这个,它对我有用

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self.tableView sizeToFit];
}
Run Code Online (Sandbox Code Playgroud)

  • 如果您的UITableView是动态的(意味着信息在运行中加载到其中),您需要将其放在别处,而不是在viewDidLoad中.对我来说,我把它放在cellForRowAtIndexPath中.还必须将"tableView"更改为我的IBOutlet属性的名称,以避免旧的"property tableView not found"错误. (3认同)

Ano*_* VM 18

在表视图上添加contentSize属性的观察者,并相应地调整帧大小

[your_tableview addObserver:self forKeyPath:@"contentSize" options:0 context:NULL];
Run Code Online (Sandbox Code Playgroud)

然后在回调中:

- (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;
    }
Run Code Online (Sandbox Code Playgroud)

希望这会帮助你.

  • 你应该再添加一件东西.您应该删除表视图的观察者.因为如果单元格已释放,它将崩溃. (2认同)

Sre*_* VR 12

斯威夫特 5 解决方案

请遵循以下四个步骤:

  1. 设置故事板中表格视图的高度约束。

  2. 从故事板中拖动高度约束并@IBOutlet在视图控制器文件中为其创建。

    @IBOutlet var tableViewHeightConstraint: NSLayoutConstraint!
    
    Run Code Online (Sandbox Code Playgroud)
  3. 为 contentSize 属性添加一个观察者override func viewDidLoad()

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

Run Code Online (Sandbox Code Playgroud)
  1. 然后您可以使用以下代码动态更改表格的高度:

    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
                 }
    
             }
         }
     }
    
    Run Code Online (Sandbox Code Playgroud)


xin*_*nil 8

如果您不想自己跟踪表视图的内容大小更改,您可能会发现此子类很有用.

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
    }
}
Run Code Online (Sandbox Code Playgroud)


Gul*_*ulz 8

我在滚动视图中有一个表格视图,必须计算出表格视图的高度并相应地调整其大小。这些是我采取的步骤:

0)将UIView添加到您的scrollView中(可能无需此步骤即可工作,但我这样做是为了避免任何可能的冲突)-这将是表视图的容器视图。如果执行此步骤,则将视图边框设置为tableview的边框。

1)创建UITableView的子类:

class IntrinsicTableView: UITableView {

    override var contentSize:CGSize {
        didSet {
            self.invalidateIntrinsicContentSize()
        }
    }

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

}
Run Code Online (Sandbox Code Playgroud)

2)在Storyboard中将表视图的类设置为IntrinsicTableView:屏幕快照:http : //joxi.ru/a2XEENpsyBWq0A

3)将heightConstraint设置为表格视图

4)将表格的IBoutlet拖到ViewController

5)将表格高度约束的IBoutlet拖到ViewController

6)将此方法添加到您的ViewController中:

override func viewWillLayoutSubviews() {
        super.updateViewConstraints()
        self.yourTableViewsHeightConstraint?.constant = self.yourTableView.intrinsicContentSize.height
    }
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助


Nik*_*iki 7

我的做法有点不同,实际上我的 TableView 在滚动视图内,所以我必须将高度约束设置为 0。

然后在运行时我做了以下更改,

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    self.viewWillLayoutSubviews()
}

override func viewWillLayoutSubviews() {
    super.updateViewConstraints()
    DispatchQueue.main.async {
        self.tableViewHeightConstraint?.constant = self.myTableView.contentSize.height
        self.view.layoutIfNeeded()
    }
}
Run Code Online (Sandbox Code Playgroud)


Yoh*_*ani 5

如果您的 contentSize 不正确,这是因为它基于估计的行高度(自动),请在此之前使用

tableView.estimatedRowHeight = 0;

来源:https : //forums.developer.apple.com/thread/81895