Resizing UITableView to fit content
Asked Answered
L

25

218

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?

Landman answered 7/4, 2010 at 19:0 Comment(4)
For anyone looking to do a similar thing on OSX, see this question: #11322639Quay
@Landman hi, can you explain what's wrong with the "sizeToFit" approach please ?:)Howsoever
“I would like to find a "sizeToFit" work around”. So have you or haven't you tried UIView's - sizeToFit method?Deck
can I ask question related to this? I have used your approach but haven't set parent tableview height to child tableview content sizeWindcheater
L
170

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;
    });
Landman answered 7/4, 2010 at 19:29 Comment(10)
It's possible to run into problems with this method. If you have a large list, it's possible that the height of the frame will cutoff some of your cells. You can see this happen if you have bouncing enabled and scroll to the bottom to see some cells bounce out of view.Willow
Where exactly did you specify the height? Did you make a call to reloadData and resize it afterwords?Dorinda
Where's the best place to put this code? I tried it in viewDidLoad and it didn't work presumably because the tableview delegate methods hadn't fired yet. Which delegate method is best?Hylozoism
I did this is viewDidAppear, and it seems to have worked. Note that the tableview might be a bit taller than its content because it leaves a bit of space for a section header and footerLoran
the question is where to place this code if I have a dynamic table. It means I have clickable section view and it shows or hides its rows on clickMaybellemayberry
Works like charm, just dont forget to run that code inside the main thread with: dispatch_async(dispatch_get_main_queue()) { //modify UI elements here} ...otherwise, the changes will not be visibleOtherwhere
I've found that viewDidAppear is a great place to put stuff you want to happen after all initial tableView cellForRowAtIndexPath calls have finishedDetour
This solution is hacky because you have to write this everytime you need this behaviour. Also it leads to cluttered code because even more TableView-related code is spread all over your view controller class. Have a look at my answer: https://mcmap.net/q/125266/-resizing-uitableview-to-fit-content that completely relies on Auto-Layout and is super generic :-)Oriya
@KyleClegg best part is where you are setting up array. Add this code in didSet blockCordova
Superb. You saved me boss.Specie
O
196

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

Oriya answered 5/2, 2018 at 13:28 Comment(21)
Very good answer, it worked out for me, thanks. One thing though - in my case I needed to change the class of the tableView to be IntrinsicTableView in the storyboard. I didn't need to embed my table view within another UIView.Sorcery
Yeah you're right. I updated my answer. Step 2 could be read like you said. Of course I meant to set the tableView to IntrinsicTableView. Also an extra wrapping UIView isn't necessary. You can use any existing parent view of course :)Oriya
Swift 4 This worked for me just fine tableView.sizeToFit()Culottes
Yeah that may be a good solution, if your content is static. With my approach you can use Auto-Layout to embed a tableView with dynamic content in other views and keep it in full height all the time, without thinking about at what places sizeToFit() needs to be calledOriya
FYI: Improved naming and removed unnecessary explicit selfs.Stepheniestephens
it worked for me, but had to add this: override func viewWillLayoutSubviews() { DispatchQueue.main.async { self.tableViewHeightConstraint.constant = self.tableView.contentSize.height } }Groth
I have a splitviewcontroller and would like to put a UIImage at the bottom of a static table view in the master. Would this approach, sub-classing UITableView be the correct approach?Ptero
No, this solution is for occurrences where you embed a table view inside some other view and need to have it exactly the height its content has. You should take a look at tableFooterView or viewForFooterInSectionOriya
Wonderful Thankyou!. Finally match parent and wrap content for tableview...Acklin
This solution does not work if you are not using storyboards.Acklin
I use it all the time in storyboards, did you follow all the steps? If yes, could you explain your view hierarchy? @AmberKOriya
Yes the only issue is it doesn't accounts automatic content insets behavior eg if navigation bar and status bar height. In this case it scrolls within that range.Acklin
This is the only solution I found working great for me. Any other answers made me find the last cell cut off or search more with disappointment . xDHomebody
Doesn't work in smaller screens when your tableview is inside a cell.Acklin
This also works in scenarios where the tableview has a border and I wanted the border to cover only the visible cells, but making the bottom constraint a placeholder may cause the tableview to grow outside the screen. Instead, I unchecked the placeholder box and made the bottom constraint >= 0, and it worked perfectly!Brooke
How can i update tableView's height to match reloaded data's height? in my case after fetching data tableView doesnt want to relayout with new height. This works when data is provided before thoForceful
Two things: 1) make sure to set the bottom constraint to >= (greaterThanOrEqual) 2) If you're setting backgroundView for an empty table message, replace intrinsicContentSize with: ``` override var intrinsicContentSize: CGSize { layoutIfNeeded() if contentSize.height > 0 { return CGSize(width: UIView.noIntrinsicMetric, height: contentSize.height) } else { return super.intrinsicContentSize } } ```Jerz
This solution is great but I can't find any way to resize the tableView's height in an animated fashion. I have a resizable cell which (when used with a regular tableView) "pushes" the bottom of the tableView when expanded and shrinks the tableView when collapsed. I achieved this when using the extension but it just won't animate it and it looks really badMeasly
@fl034 can I ask question related to this? I have used your approach but haven't set parent tableview height to child tableview content size.Windcheater
@Windcheater I'd recommend you to open a new question. My answer doesn't cover nested tableviewsOriya
@fl034 Thank you, yes I have already opened a new question. Do you mind if you have a time can check please? Link: #66314230Windcheater
L
170

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;
    });
Landman answered 7/4, 2010 at 19:29 Comment(10)
It's possible to run into problems with this method. If you have a large list, it's possible that the height of the frame will cutoff some of your cells. You can see this happen if you have bouncing enabled and scroll to the bottom to see some cells bounce out of view.Willow
Where exactly did you specify the height? Did you make a call to reloadData and resize it afterwords?Dorinda
Where's the best place to put this code? I tried it in viewDidLoad and it didn't work presumably because the tableview delegate methods hadn't fired yet. Which delegate method is best?Hylozoism
I did this is viewDidAppear, and it seems to have worked. Note that the tableview might be a bit taller than its content because it leaves a bit of space for a section header and footerLoran
the question is where to place this code if I have a dynamic table. It means I have clickable section view and it shows or hides its rows on clickMaybellemayberry
Works like charm, just dont forget to run that code inside the main thread with: dispatch_async(dispatch_get_main_queue()) { //modify UI elements here} ...otherwise, the changes will not be visibleOtherwhere
I've found that viewDidAppear is a great place to put stuff you want to happen after all initial tableView cellForRowAtIndexPath calls have finishedDetour
This solution is hacky because you have to write this everytime you need this behaviour. Also it leads to cluttered code because even more TableView-related code is spread all over your view controller class. Have a look at my answer: https://mcmap.net/q/125266/-resizing-uitableview-to-fit-content that completely relies on Auto-Layout and is super generic :-)Oriya
@KyleClegg best part is where you are setting up array. Add this code in didSet blockCordova
Superb. You saved me boss.Specie
D
123

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()
}
Diagnostics answered 27/9, 2016 at 15:33 Comment(3)
This solution always cut off the last row on Xcode 8.3 for me.Cinderellacindi
I had to put this in the cellForRowAtIndexPath: method. If I put it in the viewWillLayoutSubviews method, the computed contentSize height is based on the estimated height, not the actual content height.Sight
I had to use self.view.layoutIfNeeded() at the end to resize the table properly and some cases you may have to embed whole code in a dispatch block for the main thread as it is UI essential taskProportion
P
22

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

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self.tableView sizeToFit];
}
Participate answered 24/10, 2013 at 15:21 Comment(2)
If your UITableView is dynamic (meaning information loads to and from it on the fly), you'll need to put this elsewhere, not in viewDidLoad. For me, I put it in cellForRowAtIndexPath. Also had to change "tableView" to the name of my IBOutlet property to avoid the old "property tableView not found" error.Esdraelon
thx, had problem with resizing tableview inside popover, it workedFalbala
H
19

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.

Heder answered 21/8, 2014 at 5:15 Comment(1)
You should add one more thing. You should remove the observer for the table view. Because it will crash if cell deallocated.Periostitis
Z
19

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

Ziguard answered 2/2, 2018 at 10:4 Comment(5)
See my answer which is based on your subclass but doesn't need any setting of height constraints.Oriya
@fl034 provide link?Ziguard
@fl034 I do not think you can avoid using constraints when your elements are embedded into the Scroll View) My case is with the ScrollViewZiguard
I also have my table view inside a scroll view and it works perfectly :)Oriya
works for me on iOS 13/Xcode 11 You've put an end to 3 days of suffering kind sir, thank youSedulity
P
12

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
                 }
    
             }
         }
     }
    
Piliform answered 13/11, 2020 at 2:38 Comment(0)
T
8

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
    }
}
Triumphant answered 17/2, 2017 at 9:42 Comment(2)
For swift 3, intrinsicContentSize has become a var, like override public var intrinsicContentSize: CGSize { //... return someCGSize }Cabasset
not working for me. still hiding bottom of the tableZiguard
S
8

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()
    }
}
Sudatorium answered 4/12, 2019 at 8:8 Comment(1)
Perfect Ans if your TableView is in ScrollViewTourney
A
7

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

Aceydeucy answered 13/4, 2018 at 11:45 Comment(0)
L
4

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.

Lafayette answered 31/8, 2017 at 8:12 Comment(2)
This is very simple solution, it worked for me, Thank you @Dorde NilovicDinnage
@DoedeNilovic I am trying to to use your second solution as I am using tableviewcell inside tableviewcell. I am not able to get insidetableviewcell height as the 90.0 is static I need it dynamic. Can you share some code for it. PleaseCredulity
H
3

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.

Hydrokinetic answered 26/3, 2020 at 17:47 Comment(0)
T
2

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
            }
        }
    }
}
Tumbrel answered 9/5, 2017 at 9:9 Comment(1)
You can improve on this. Add an additional constraint on your tableview, say, height <= 10000. Use control-drag from Interface Builder to your .h file to make this constraint a property of your view controller. Then you can avoid iterating through constraints and searching. Just directly set myTableHeightConstraint.constant = tableView.contentSize.heightVilliform
V
2

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()
}
Vickers answered 17/2, 2021 at 9:0 Comment(0)
T
1

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;
}
Tiernan answered 7/10, 2015 at 5:2 Comment(0)
R
1

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
Rosana answered 4/12, 2019 at 1:23 Comment(0)
S
1

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.

Sneaking answered 6/10, 2022 at 5:42 Comment(0)
P
1

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

Proportional answered 9/11, 2023 at 10:12 Comment(0)
M
0

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"];
}
Mahan answered 11/3, 2016 at 16:47 Comment(0)
D
0

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;
}
Devlin answered 6/9, 2017 at 11:57 Comment(0)
G
0

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

Genesa answered 31/3, 2018 at 5:28 Comment(0)
B
0

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);
        }
    }
}
Bowen answered 3/7, 2019 at 22:6 Comment(0)
A
0

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

Arching answered 16/11, 2020 at 1:3 Comment(0)
C
-1

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.

Clywd answered 5/8, 2019 at 9:9 Comment(1)
Don't use word above because answers could be shuffled.Ida
E
-3

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;        
}
Embrocation answered 17/8, 2017 at 18:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.