8

I have a UITableView (let's call it tbl_A) inside a table view cell whose height is dynamic and set by UITableViewAutomaticDimension. tbl_A's cell height is also dynamic, and I know tbl_A's data won't be too much. So I want tbl_A to be scroll disabled and its frame.size equals its content size. I tried to set tbl_A's frame.size.height = tbl_A.contentSize.height, unfortunately, the height is wrong.

By the way, I don't have to use UITableView to accomplish this task. I just want to a way to display all data. Any suggestions?

This is the effect I want to achieve: enter image description here

gikygik
  • 421
  • 9
  • 26
YON
  • 1,607
  • 3
  • 18
  • 33

7 Answers7

10

Simple ;)

override var intrinsicContentSize: CGSize {
    return contentSize
}
Emad
  • 669
  • 8
  • 21
  • 1
    can you explain with more details? – ARS Nov 01 '17 at 08:02
  • From the documentation: `Setting this property allows a custom view to communicate to the layout system what size it would like to be based on its content.` https://developer.apple.com/documentation/uikit/uiview/1622600-intrinsiccontentsize – Emad Nov 01 '17 at 09:57
  • Nice! This should be the answer – Trev14 Aug 11 '18 at 00:24
  • 1
    I don't think this is a very good answer at all no detail at all, I read another answer that basically offers the same solution as this one - but the person writing it went into more detail rather than just calling the solution 'simple'. https://stackoverflow.com/a/52248020/4309446 – James Wolfe Dec 05 '18 at 14:43
  • @JamesWolfe please read the documentation about `intrinsicContentSize` at https://developer.apple.com/documentation/uikit/uiview/1622600-intrinsiccontentsize When using auto layout and setting constraints this property sets the default size of the view. So make it return the content size of your table view and it's what you want. – Emad Dec 10 '18 at 23:39
  • 1
    I understand what you're doing - I just think it lacks explaination of any kind, maybe add that comment about documentation to your answer? – James Wolfe Dec 11 '18 at 09:46
  • Very elegant. However you need to make sure to call `invalidateIntrinsicContentSize` in `contentSize` `didSet` – de. Feb 06 '20 at 12:27
7

Based on @Emad's answer but with the important addition to invalidate the intrinsic content size if the contentSize changes.

class ContentWrappingTableView: UITableView {

  override var intrinsicContentSize: CGSize {
    return self.contentSize
  }

  override var contentSize: CGSize {
    didSet {
        self.invalidateIntrinsicContentSize()
    }
  }
}
de.
  • 7,068
  • 3
  • 40
  • 69
2

As long as scrolling is locked, you can use the following to match the tableView's layout dynamically.:

    let size = actionsViewController.view.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)
    actionsViewController.view.frame.size = size
    actionsViewController.preferredContentSize = size

The following presents a way to have auto layout calculate the height for you and provide you a size based on restrictions you pass in. Another way could be the following:

    CGFloat leftViewHeight = 0;
    if (self.isExpanded) {
        [self.lineItemLineNumberListTableViewController.tableView layoutIfNeeded];
        UITableView *tableView = self.lineItemLineNumberListTableViewController.tableView;
        CGSize tableViewContentSize = tableView.contentSize;
        leftViewHeight = tableViewContentSize.height;
    }

self.leftViewHeightConstraint.constant = leftViewHeight;

I had previously used the above to expand dynamically resizing cells with dynamic subviews within them. This configures a height constraint based on the content size AFTER reloading the tableView's content to ensure the content was loaded prior to adjusting the size.

TheCodingArt
  • 3,436
  • 4
  • 30
  • 53
1

1) Add to your class reference to constraint:

var heightC: NSLayoutConstraint!

2) Disable scroll and add height constraint:

tableView.scrollEnabled = false
heightC = tableView.autoSetDimension(.Height, toSize: 20) // using PureLayout library

3) override viewDidLayoutSubviews of your controller:

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    heightC.constant = tableView.contentSize.height
}

and set height constraint "constant" attribute to tableview content height.

4) on data refresh (for example when item count changes from 0 to more) just force main controller view to layout:

view.setNeedsLayout()
Leszek Zarna
  • 3,253
  • 26
  • 26
0
  1. For your case you can also use scrollView.
  2. In that scrollView while adding each subcell keep track of each subcell by adding each subcell's height ( take variable as referenceHeight )
  3. finally set the scrollview height by calculated height(referenceHeight)
samanvith
  • 39
  • 3
0

Below is method to find tableView's content size.

- (CGFloat)tableViewHeightOfTable:(UITableView *)table
{
   [table layoutIfNeeded];
   return [table contentSize].height;
}

Make sure that you call this method after reloading your table like below code.

[YourTable reloadData];
YourTable.frame.size.height = [self tableViewHeightOfTable:YourTable];
Rahul Patel
  • 5,858
  • 6
  • 46
  • 72
  • 1
    I think this `contentSize` is calculated based on `estimatedRowHeight` which is not accurate. In the end, I used OAStackView as my container view. – YON Jan 27 '16 at 07:32
  • Can you share your solution in detail? i am struggling for the same issue. – ARS Nov 01 '17 at 07:52
-2

In your case tableview is the best solution , you can use different uitableviewcells and sections and can load it in cellForRowAtIndexPath .

Reshmi Majumder
  • 961
  • 4
  • 15