调整 UITableView 的大小以适合内容

发布于 2024-08-28 12:56:57 字数 239 浏览 13 评论 0原文

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

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

谁能告诉我如何实现这一目标?

I am creating an app which will have a question in a UILabel and a multiple choice answers displayed in UITableView, each row showing a multiple choice. Questions and answers will vary, so I need this UITableView to be dynamic in height.

I would like to find a sizeToFit work around for the table. Where the table's frame is set to the height of all it's content.

Can anyone advise on how I can achieve this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(25

千年*琉璃梦 2024-09-04 12:56:58

设置tableview重新加载时

self.tableView.reloadData()

只需调用下面一个即可处理内容大小

self.view.layoutIfNeeded()

处理逻辑

if self.tableView.contentSize.height > self.tableView.frame.size.height {
     // Handler here
} else {
     // Handler here
}
     

self.view.layoutIfNeeded()是获取准确内容大小的关键

When setting tableview reload

self.tableView.reloadData()

Just call below one to get worked on content size

self.view.layoutIfNeeded()

To handle logic

if self.tableView.contentSize.height > self.tableView.frame.size.height {
     // Handler here
} else {
     // Handler here
}
     

self.view.layoutIfNeeded() is the key to getting the exact content size

岁月静好 2024-09-04 12:56:58

作为 Anooj VM 答案的扩展,我建议执行以下操作仅在内容大小发生变化时刷新内容大小。

这种方法还可以正确禁用滚动支持更大的列表旋转。不需要dispatch_async,因为contentSize更改是在主线程上调度的。

- (void)viewDidLoad {
        [super viewDidLoad];
        [self.tableView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:NULL]; 
}


- (void)resizeTableAccordingToContentSize:(CGSize)newContentSize {
        CGRect superviewTableFrame  = self.tableView.superview.bounds;
        CGRect tableFrame = self.tableView.frame;
        BOOL shouldScroll = newContentSize.height > superviewTableFrame.size.height;
        tableFrame.size = shouldScroll ? superviewTableFrame.size : newContentSize;
        [UIView animateWithDuration:0.3
                                    delay:0
                                    options:UIViewAnimationOptionCurveLinear
                                    animations:^{
                            self.tableView.frame = tableFrame;
        } completion: nil];
        self.tableView.scrollEnabled = shouldScroll;
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
    if ([change[NSKeyValueChangeKindKey] unsignedIntValue] == NSKeyValueChangeSetting &&
        [keyPath isEqualToString:@"contentSize"] &&
        !CGSizeEqualToSize([change[NSKeyValueChangeOldKey] CGSizeValue], [change[NSKeyValueChangeNewKey] CGSizeValue])) {
        [self resizeTableAccordingToContentSize:[change[NSKeyValueChangeNewKey] CGSizeValue]];
    } 
}

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
    [super didRotateFromInterfaceOrientation:fromInterfaceOrientation];
    [self resizeTableAccordingToContentSize:self.tableView.contentSize]; }

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

As an extension of Anooj VM's answer, I suggest the following to refresh content size only when it changes.

This approach also disable scrolling properly and support larger lists and rotation. There is no need to dispatch_async because contentSize changes are dispatched on main thread.

- (void)viewDidLoad {
        [super viewDidLoad];
        [self.tableView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:NULL]; 
}


- (void)resizeTableAccordingToContentSize:(CGSize)newContentSize {
        CGRect superviewTableFrame  = self.tableView.superview.bounds;
        CGRect tableFrame = self.tableView.frame;
        BOOL shouldScroll = newContentSize.height > superviewTableFrame.size.height;
        tableFrame.size = shouldScroll ? superviewTableFrame.size : newContentSize;
        [UIView animateWithDuration:0.3
                                    delay:0
                                    options:UIViewAnimationOptionCurveLinear
                                    animations:^{
                            self.tableView.frame = tableFrame;
        } completion: nil];
        self.tableView.scrollEnabled = shouldScroll;
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
    if ([change[NSKeyValueChangeKindKey] unsignedIntValue] == NSKeyValueChangeSetting &&
        [keyPath isEqualToString:@"contentSize"] &&
        !CGSizeEqualToSize([change[NSKeyValueChangeOldKey] CGSizeValue], [change[NSKeyValueChangeNewKey] CGSizeValue])) {
        [self resizeTableAccordingToContentSize:[change[NSKeyValueChangeNewKey] CGSizeValue]];
    } 
}

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
    [super didRotateFromInterfaceOrientation:fromInterfaceOrientation];
    [self resizeTableAccordingToContentSize:self.tableView.contentSize]; }

- (void)dealloc {
    [self.tableView removeObserver:self forKeyPath:@"contentSize"];
}
太傻旳人生 2024-09-04 12:56:58

Musa almatri 的 objc 版本

(void)viewWillLayoutSubviews
{
    [super updateViewConstraints];
    CGFloat desiredHeight = self.tableView.contentSize.height;
    // clamp desired height, if needed, and, in that case, leave scroll Enabled
    self.tableHeight.constant = desiredHeight;
    self.tableView.scrollEnabled = NO;
}

objc version of Musa almatri

(void)viewWillLayoutSubviews
{
    [super updateViewConstraints];
    CGFloat desiredHeight = self.tableView.contentSize.height;
    // clamp desired height, if needed, and, in that case, leave scroll Enabled
    self.tableHeight.constant = desiredHeight;
    self.tableView.scrollEnabled = NO;
}
舟遥客 2024-09-04 12:56:58

您可以尝试

使用 Storyboard 或以编程方式使用此自定义 AGTableView 设置 TableView 高度约束。 (此类自动获取高度约束并将内容视图高度设置为您的表视图高度)。

class AGTableView: UITableView {

    fileprivate var heightConstraint: NSLayoutConstraint!

    override init(frame: CGRect, style: UITableViewStyle) {
        super.init(frame: frame, style: style)
        self.associateConstraints()
    }

    required public init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.associateConstraints()
    }

    override open func layoutSubviews() {
        super.layoutSubviews()

        if self.heightConstraint != nil {
            self.heightConstraint.constant = self.contentSize.height
        }
        else{
            self.sizeToFit()
            print("Set a heightConstraint to Resizing UITableView to fit content")
        }
    }

    func associateConstraints() {
        // iterate through height constraints and identify

        for constraint: NSLayoutConstraint in constraints {
            if constraint.firstAttribute == .height {
                if constraint.relation == .equal {
                    heightConstraint = constraint
                }
            }
        }
    }
}

注意如果设置高度有任何问题,请使用yourTableView.layoutSubviews()

You can try Out this Custom AGTableView

To Set a TableView Height Constraint Using storyboard or programmatically. (This class automatically fetch a height constraint and set content view height to yourtableview height).

class AGTableView: UITableView {

    fileprivate var heightConstraint: NSLayoutConstraint!

    override init(frame: CGRect, style: UITableViewStyle) {
        super.init(frame: frame, style: style)
        self.associateConstraints()
    }

    required public init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.associateConstraints()
    }

    override open func layoutSubviews() {
        super.layoutSubviews()

        if self.heightConstraint != nil {
            self.heightConstraint.constant = self.contentSize.height
        }
        else{
            self.sizeToFit()
            print("Set a heightConstraint to Resizing UITableView to fit content")
        }
    }

    func associateConstraints() {
        // iterate through height constraints and identify

        for constraint: NSLayoutConstraint in constraints {
            if constraint.firstAttribute == .height {
                if constraint.relation == .equal {
                    heightConstraint = constraint
                }
            }
        }
    }
}

Note If any problem to set a Height then yourTableView.layoutSubviews().

冷情妓 2024-09-04 12:56:58

我正在使用 UIView 扩展,方法接近上面的 @ChrisB 方法

 extension UIView {
func updateHeight(_ height:NSLayoutConstraint)
{
    
    let newSize = CGSize(width: self.frame.size.width, height: CGFloat(MAXFLOAT))
    let fitSize : CGSize = self.sizeThatFits(newSize)
    
    height.constant = fitSize.height
    
   
}
}

实现:

@IBOutlet weak var myTableView: UITableView!
@IBOutlet weak var myTableVieweHeight: NSLayoutConstraint!
//(call it whenever tableView is updated inside/outside delegate methods)
myTableView.updateHeight(myTableVieweHeigh)

奖励:可以在任何其他 UIView 上使用,例如:你自己的动态标签

I am using a UIView extension , approach is close to @ChrisB approach above

 extension UIView {
func updateHeight(_ height:NSLayoutConstraint)
{
    
    let newSize = CGSize(width: self.frame.size.width, height: CGFloat(MAXFLOAT))
    let fitSize : CGSize = self.sizeThatFits(newSize)
    
    height.constant = fitSize.height
    
   
}
}

implementation : :

@IBOutlet weak var myTableView: UITableView!
@IBOutlet weak var myTableVieweHeight: NSLayoutConstraint!
//(call it whenever tableView is updated inside/outside delegate methods)
myTableView.updateHeight(myTableVieweHeigh)

Bonus : Can be used on any other UIViews eg:your own dynamic label

眉黛浅 2024-09-04 12:56:58

基于fl034的答案。但对于 Xamarin.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);
        }
    }
}

Based on answer of fl034. But for Xamarin.iOS users:

[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);
        }
    }
}
伤感在游骋 2024-09-04 12:56:58

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

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

If you want your table to be dynamic, you will need to use a solution based on the table contents as detailed above. If you simply want to display a smaller table, you can use a container view and embed a UITableViewController in it - the UITableView will be resized according to the container size.

This avoids a lot of calculations and calls to layout.

简美 2024-09-04 12:56:58

Swift 3 中的 Mu 解决方案:在 viewDidAppear 中调用此方法

func UITableView_Auto_Height(_ t : UITableView)
{
        var frame: CGRect = t.frame;
        frame.size.height = t.contentSize.height;
        t.frame = frame;        
}

Mu solution for this in swift 3: Call this method in viewDidAppear

func UITableView_Auto_Height(_ t : UITableView)
{
        var frame: CGRect = t.frame;
        frame.size.height = t.contentSize.height;
        t.frame = frame;        
}
沫尐诺 2024-09-04 12:56:57

无需 KVO、DispatchQueue 或自行设置约束的 Swift 5 和 4.2 解决方案。

此解决方案基于 Gulz 的回答< /a>.

  1. 创建UITableView的子类:

    导入 UIKit
    
    最终类 ContentSizedTableView: UITableView {
        覆盖 var contentSize:CGSize {
            没有设置{
                invalidateIntrinsicContentSize()
            }
        }
    
        覆盖 var 内在内容大小:CGSize {
            布局如果需要()
            返回 CGSize(宽度: UIView.noIntrinsicMetric, 
                         高度:contentSize.height + adjustmentContentInset.top)
        }
    }
    
  2. UITableView 添加到您的布局并在所有方面设置约束。设置底部约束关系为>=(greaterThanOrEqual)。

  3. 将其自定义类设置为ContentSizedTableView

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


更新: 已更改 Swift 4.2 的代码。如果您使用的是早期版本,请使用 UIViewNoIntrinsicMetric 而不是 UIView.noIntrinsicMetric

Swift 5 and 4.2 solution without KVO, DispatchQueue, or setting constraints yourself.

This solution is based on Gulz's answer.

  1. Create a subclass of 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 + adjustedContentInset.top)
        }
    }
    
  2. Add a UITableView to your layout and set constraints on all sides. Set the bottom constraint relation to >= (greaterThanOrEqual).

  3. Set the custom class of it to ContentSizedTableView.

  4. You should see some errors, because Storyboard doesn't take our subclass' intrinsicContentSize into account. Fix this by opening the size inspector and overriding the intrinsicContentSize to a placeholder value. This is an override for design time. At runtime it will use the override in our ContentSizedTableView class


Update: Changed code for Swift 4.2. If you're using a prior version, use UIViewNoIntrinsicMetric instead of UIView.noIntrinsicMetric

阿楠 2024-09-04 12:56:57

其实我自己也找到了答案。

我只是为 tableView.frame 创建一个新的 CGRect ,其 heighttable.contentSize.height

设置UITableView 的高度与其内容的height 之比。
由于代码修改了 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;
    });

Actually I found the answer myself.

I just create a new CGRect for the tableView.frame with the height of table.contentSize.height

That sets the height of the UITableView to the height of its content.
Since the code modifies the UI, do not forget to run it in the main thread:

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;
    });
命比纸薄 2024-09-04 12:56:57

Swift 解决方案

请按照以下步骤操作:

  1. 从 Storyboard 设置表格的高度约束。

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

    @IBOutlet var tableHeight:NSLayoutConstraint!
    
  3. 然后您可以使用以下代码动态更改表格的高度:

    覆盖 func viewWillLayoutSubviews() {
        super.updateViewConstraints()
        self.tableHeight?.constant = self.table.contentSize.height
    }
    

如果最后一行被截断,请尝试在 willDisplay cell 函数中调用 viewWillLayoutSubviews()

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

Swift Solution

Follow these steps:

  1. Set the height constraint for the table from the storyboard.

  2. Drag the height constraint from the storyboard and create @IBOutlet for it in the view controller file.

    @IBOutlet var tableHeight: NSLayoutConstraint!
    
  3. Then you can change the height for the table dynamicaly using this code:

    override func viewWillLayoutSubviews() {
        super.updateViewConstraints()
        self.tableHeight?.constant = self.table.contentSize.height
    }
    

If the last row is cut off, try to call viewWillLayoutSubviews() in willDisplay cell function:

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    self.viewWillLayoutSubviews()
}
遥远的绿洲 2024-09-04 12:56:57

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

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

I've tried this in iOS 7 and it worked for me

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self.tableView sizeToFit];
}
一瞬间的火花 2024-09-04 12:56:57

在表视图上为 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;
    }

希望这会对您有所帮助。

Add an observer for the contentSize property on the table view, and adjust the frame size accordingly

[your_tableview addObserver:self forKeyPath:@"contentSize" options:0 context:NULL];

then in the callback:

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

Hope this will help you.

享受孤独 2024-09-04 12:56:57

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

0)将 UIView 添加到您的滚动视图(可能没有此步骤也可以工作,但我这样做是为了避免任何可能的冲突)-这将是您的表视图的容器视图。如果执行此步骤,请将视图边框设置为表格视图的边框。

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

}

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
    }

Hope这有帮助

I had a table view inside scroll view and had to calculate tableView's height and resize it accordingly. Those are steps I've taken:

0) add a UIView to your scrollView (probably will work without this step but i did it to avoid any possible conflicts) - this will be a containr view for your table view. If you take this step , then set the views borders right to tableview's ones.

1) create a subclass of UITableView:

class IntrinsicTableView: UITableView {

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

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

}

2) set class of a table view in Storyboard to IntrinsicTableView: screenshot: http://joxi.ru/a2XEENpsyBWq0A

3) Set the heightConstraint to your table view

4) drag the IBoutlet of your table to your ViewController

5) drag the IBoutlet of your table's height constraint to your ViewController

6) add this method into your ViewController:

override func viewWillLayoutSubviews() {
        super.updateViewConstraints()
        self.yourTableViewsHeightConstraint?.constant = self.yourTableView.intrinsicContentSize.height
    }

Hope this helps

假面具 2024-09-04 12:56:57

Swift 5 解决方案

请遵循以下四个步骤:

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

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

    @IBOutlet var tableViewHeightConstraint:NSLayoutConstraint!
    
  3. 重写函数 viewDidLoad() 上添加 contentSize 属性的观察者

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

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

    覆盖 funcobserveValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
         if(keyPath == "内容大小"){
             如果让 newvalue = 改变?[.newKey]
             {
                 DispatchQueue.main.async {
                 让newsize = newvalue为! CG大小
                 self.tableViewHeightConstraint.constant = newsize.height
                 }
    
             }
         }
     }
    

Swift 5 Solution

Follow these four steps:

  1. Set the height constraint for the tableview from the storyboard.

  2. Drag the height constraint from the storyboard and create @IBOutlet for it in the view controller file.

    @IBOutlet var tableViewHeightConstraint: NSLayoutConstraint!
    
  3. Add an observer for the contentSize property on the override func viewDidLoad()

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

  1. 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
                 }
    
             }
         }
     }
    
陌上青苔 2024-09-04 12:56:57

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

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

In case you don't want to track table view's content size changes yourself, you might find this subclass useful.

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
    }
}
忆悲凉 2024-09-04 12:56:57

我的做法有点不同,实际上我的 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()
    }
}

I did in a bit different way, Actually my TableView was inside scrollview so i had to give height constraint as 0.

Then at runtime I made following changes,

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()
    }
}
巴黎夜雨 2024-09-04 12:56:57

如果您的 contentSize 不正确,这是因为它基于estimatedRowHeight(自动),请在之前使用它

tableView.estimatedRowHeight = 0;

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

In case your contentSize is not correct this is because it is based on the estimatedRowHeight (automatic), use this before

tableView.estimatedRowHeight = 0;

source : https://forums.developer.apple.com/thread/81895

心头的小情儿 2024-09-04 12:56:57

Swift 3、iOS 10.3

解决方案 1:
只需将 self.tableview.sizeToFit() 放入 cellForRowAt indexPath 函数中即可。确保将桌面视图高度设置得高于您的需要。
如果您没有 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:
在 Storyboard 中设置 tableview 高度约束并将其拖动到 ViewController。如果您知道单元格的平均高度并且知道数组包含多少个元素,则可以执行以下操作:

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

*编辑:

在我尝试了所有解决方案并且每个解决方案都在修复某些问题之后,但不完全, this 是完全解释和解决此问题的答案。

Swift 3, iOS 10.3

Solution 1:
Just put self.tableview.sizeToFit() in cellForRowAt indexPath function. Make sure to set tableview height higher then you need.
This is a good solution if you don't have views below tableview. However, if you have, bottom tableview constraint will not be updated (I didn't try to fix it because I came up with solution 2)

Example:

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

Solution 2:
Set tableview height constraint in storyboard and drag it to the ViewController. If you know the average height of your cell and you know how many elements your array contains, you can do something like this:

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

*EDIT:

After all the solutions I tried and every of them was fixing something, but not completely, this is the answer that explains and fixes this problem completely.

青萝楚歌 2024-09-04 12:56:57

这对我来说很有效,使用自动布局,表格视图只有一个部分。

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.zero,因此我需要设置边界以便能够遵守单元格定义的自动布局规则。我将大小设置为应该足够大的任意值。实际尺寸将由自动布局系统稍后计算。

This works for me using Auto Layout, with a table view with only one section.

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
}

I call this function when setting up Auto Layout (The sample here uses SnapKit, but you get the idea):

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

I want the UITableView only to be as tall as the combined height of the cells; I loop through the cells and accumulate the total height of the cells. Since the size of the table view is CGRect.zero at this point, I need to set the bounds to be able to respect the Auto Layout rules defined by the cell. I set the size to an arbitrary value that should be large enough. The actual size will be calculated later by the Auto Layout system.

眼前雾蒙蒙 2024-09-04 12:56:57

如果使用自动布局,有一个更好的方法:更改确定高度的约束。只需计算表格内容的高度,然后找到约束并更改它。这是一个示例(假设确定桌子高度的约束实际上是具有关系“等于”的高度约束):

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

There is a much better way to do it if you use AutoLayout: change the constraint that determines the height. Just calculate the height of your table contents, then find the constraint and change it. Here's an example (assuming that the constraint that determines your table's height is actually a height constraint with relation "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
            }
        }
    }
}
一桥轻雨一伞开 2024-09-04 12:56:57

基于
fl034的答案

SWift 5

var tableViewHeight: NSLayoutConstraint?

    tableViewHeight = NSLayoutConstraint(item: servicesTableView, 
    attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute,
    multiplier: 0.0, constant: 10)
    tableViewHeight?.isActive = true


  func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    tableViewHeight?.constant = tableView.contentSize.height
    tableView.layoutIfNeeded()
}

based on
fl034's answer

SWift 5

var tableViewHeight: NSLayoutConstraint?

    tableViewHeight = NSLayoutConstraint(item: servicesTableView, 
    attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute,
    multiplier: 0.0, constant: 10)
    tableViewHeight?.isActive = true


  func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    tableViewHeight?.constant = tableView.contentSize.height
    tableView.layoutIfNeeded()
}
白馒头 2024-09-04 12:56:57

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

Mimo's answer and Anooj VM 's answer both are awesome but there is a small problem if you have a large list, it's possible that the height of the frame will cutoff some of your cells.

So. I have modified the answer a little bit:

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;
}
執念 2024-09-04 12:56:57

我的 Swift 5 实现是将 tableView 的高度约束设置为其内容的大小 (contentSize.height)。此方法假设您使用自动布局。此代码应放置在 cellForRowAt 表视图方法。

tableView.heightAnchor.constraint(equalToConstant: tableView.contentSize.height).isActive = true

My Swift 5 implementation is to set the hight constraint of the tableView to the size of its content (contentSize.height). This method assumes you are using auto layout. This code should be placed inside the cellForRowAt tableView method.

tableView.heightAnchor.constraint(equalToConstant: tableView.contentSize.height).isActive = true
青朷 2024-09-04 12:56:57

就我而言,我的管理方式是。
给出表格视图的任何恒定高度。创建表视图高度的出口,然后在重新加载表视图时调用以下函数。

private func manageHeight(){
        tableViewHeight.constant=CGFloat.greatestFiniteMagnitude
        tableView.reloadData()
        tableView.layoutIfNeeded()
        tableViewHeight.constant=tableView.contentSize.height
    }

注意:tableView是表视图的出口,tableViewHeight是tableView高度的出口。

For my case, how I manage is.
give any constant height of table view. create outlet of table view height and then call the following function where ever you relaod the tableView.

private func manageHeight(){
        tableViewHeight.constant=CGFloat.greatestFiniteMagnitude
        tableView.reloadData()
        tableView.layoutIfNeeded()
        tableViewHeight.constant=tableView.contentSize.height
    }

note: tableView is the outlet for your table view and tableViewHeight is the outlet for tableView height.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文