iOS 8 auto-sizing UITableViewCell with UITextView - uitableview

iOS 8 introduced a way for tableViews to automatically adjust their cell's height based on their content (via AutoLayout).
// in viewDidLoad:
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 44.0
I already got it working with labels, images, etc.
However, I can not figure out a way for the table view cell to grow automatically as soon as a cell's text view changes?
Some more information on the setup:
The UITextView inside a cell has horizontal and vertical constraints to the table view cell's contentView. I also disabled scrolling for the text view.
I have also tried to change the height constraint of the cell manually, but the cell would not adopt those changes as well.

If everything is set up properly (Auto Layout constraints) you do not have to calculate anything yourself.
All you have to do is disable UITextView's scrolling enabled property then on textViewDidChange call tableView.beginUpdates() and tableView.endUpdates().
For a detailed explanation, check out a post I wrote which also includes a working sample project.

Reload the cell in the textViewDidBeginEditing: method of your UITextViewDelegate
[self.tableView beginUpdates];
[self.tableView reloadRowsAtIndexPaths:#[[NSIndexPath indexPathForItem:0 inSection:0]] withRowAnimation:UITableViewRowAnimationNone];
[self.tableView endUpdates];
Obviously you should change the indexpath to the correct one for your cell. This will get the cell to update its constraints and resize itself.

The tableView has to be informed that the textView has changed. Other posts usually answer a "static" textView problem. However, if you are typing inside a table, the cell needs to grow as the textView grows as you type. The textView grows by disabling scrolling. The cell grows by setting the textView's top and bottom constraints to those of the contentView of the cell. This will work once, once the table loads. However to tell the tableView to grow in real time, you have to do in the textView's didChange delegate call
func textViewChanged(onCell cell: YourCustomCell) {
UIView.setAnimationsEnabled(false)
tableView.beginUpdates()
tableView.endUpdates()
UIView.setAnimationsEnabled(true)
}
This will work as you expect. The cell will grow as you type and there won't be a "bouncing".

Solution for Swift 4
func textViewDidChange(_ textView: UITextView) {
let fixedWidth = textView.frame.size.width
let oldSize = textView.frame.size
let newSize = textView.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat(MAXFLOAT)))
if oldSize.height != newSize.height {
UIView.setAnimationsEnabled(false)
var newFrame = textView.frame
newFrame.size = CGSize(width: fmax(newSize.width, fixedWidth), height: newSize.height)
textView.frame = newFrame
self.tableView.beginUpdates()
self.tableView.endUpdates()
UIView.setAnimationsEnabled(true)
}
}

This is the function I use, which solves the problem of the table view bouncing back after every keystroke.
- (void)textViewDidChange:(UITextView *)textView {
CGFloat fixedWidth = textView.frame.size.width;
CGSize oldSize = textView.frame.size;
CGSize newSize = [textView sizeThatFits:CGSizeMake(fixedWidth, MAXFLOAT)];
// Resize cell only when cell's size changes, to prevent bouncing back and forth.
if (oldSize.height != newSize.height) {
[UIView setAnimationsEnabled:NO];
CGRect newFrame = textView.frame;
newFrame.size = CGSizeMake(fmaxf(newSize.width, fixedWidth), newSize.height);
textView.frame = newFrame;
[self.tableView beginUpdates];
[self.tableView endUpdates];
[UIView setAnimationsEnabled:YES];
}
}

You should disable scroll from your UITextView

Related

iOS - Scroll TextView to top when it's in a tableview cell

I have a UITextView inside a custom TableView cell. I want the text view to scroll to the top by default. I usually do it this way in regular views:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
let fixedWidth = bioView.frame.size.width
bioView.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat.greatestFiniteMagnitude))
let newSize = bioView.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat.greatestFiniteMagnitude))
var newFrame = bioView.frame
newFrame.size = CGSize(width: max(newSize.width, fixedWidth), height: newSize.height)
bioView.frame = newFrame;
bioView.scrollRangeToVisible(NSRange(location:0, length:0))
}
bioView is my text view object. However, this doesn't work in my case since I can't reference the textview in the ViewController class and can only do so in the CustomCell class and that class cannot override viewDidLayoutSubviews. Any help?
Try this.
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
CustomCell* cell = [tableView dequeueReusableCellWithIdentifier:#"CustomCell"];
[cell.textView scrollRangeToVisible:NSMakeRange(0, 0)];
return cell;
}
Swift 3.0:
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell", for: indexPath) as! DemoCell
cell.textView.scrollRangeToVisible(NSRange(location:0, length:0))
It works! However, the table has to scroll for the changes to take effect, best way I found so far. Thanks everyone!
In your viewController which handles UITableViewDelegate events, override willDisplayCell method. Identify your textView from Cell and write the code to scroll.
I have tried doing the scrolling, either with scrollRangeToVisible() or setting contentOffset to .zero in awakeFromNib, willDisplayCell, and cellForRowAtIndexPath. These all get executed, but the scrolling is still reset (by AutoLayout?) some time subsequent to this.
For a cell that is on screen when the UITableView appears, performing the scroll in willDisplayCell does not "stick." It does work if the cell is scrolled away and scrolls back on screen.
For a cell that is already on screen that has a UITextView with "too much" text so that it scrolls out the bottom of the TextView, the only way I have found to make the text scroll to the top is to set either scrollRangeToVisible() or contentOffset in the viewDidAppear() of the UITableViewController. Even viewWillAppear() did not work.
One drawback is that this solution causes a jump in the scroll location after the TableView appears on screen, even in a performWithoutAnimation block.
You can put the code in viewDidLayoutSubviews, and it will work, but as mentioned this gets called several times, and the text will scroll back to the top with every orientation change, which may not be desirable.

How can I adjust the UITableViewCell height to the content of UITextView that's inside?

In my story board I have a UITableView with dynamically generated UITableViewCells. Each cell contains 2 labels and 1 text view:
I have a code that adjust the size of the textfield to the amount of text:
let fixedWidth = cell.myComment.frame.size.width
cell.myComment.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat.max))
let newSize = cell.myComment.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat.max))
var newFrame = cell.myComment.frame
newFrame.size = CGSize(width: max(newSize.width, fixedWidth), height: newSize.height)
cell.myComment.frame = newFrame;
and it works fine, when I set a background color of my textView to red I see:
and the cell itself - I'm setting the size in here:
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat
{
if indexPath.row == 0 {
return 100//this is my static cell
}
else {
return 117; //for now it's hardcoded - how can I set this value dynamically based on content?
}
}
So as I wrote in the comment above - how can I set the height of the cell dynamically based on the amount of text in the text view?
The key to getting self-sizing table cells (autolayout-based, which I recommend) is as follows:
Add your subviews to the contentView of the UITableViewCell
Provide constraints between your subviews and the contentView such that your subviews reach all edges of the table cell. In your case, this probably means aligning the leading, trailing, top, and bottom edges of your UITextView to the corresponding edges of the contentView.
Set the row height to UITableViewAutomaticDimension instead of a hardcoded CGFloat.
Somewhere in your controller, provide an estimation of the height with tableView.estimatedRowHeight = x (a hard coded constant is fine, this is for performance).

Get height of each rows of UITableView

Is there any way by which I can get row height of each row in a UITableView. I have a UITableView which contains data which is dynamic, and I am using
self.tableView.rowHeight = UITableViewAutomaticDimension
to make dynamic row heights.
But I want to change height of overall UITableView as well, for that I need height of all the rows after reload of data.
I tried using
self.tableView.layoutIfNeeded()
self.tableViewHeightContraint.constant = self.tableView.contentSize.height
But due to unknown reason it is giving me height less than what exactly it has, after I add 3 or 4 records in UITableView so thinking of other way around. To calculate height of each rows and then summing them up.
I am doing in Xcode 7.2, iOS 9 and Swift 2
var dictionaryOfCellHeight = [Int : CGFloat]()
var dataArray = [String]()
func tableView(tableView: UITableView!, heightForRowAtIndexPath indexPath: NSIndexPath!) -> CGFloat {
if dictionaryOfCellHeight[indexPath.row] == nil
{
var frame : CGRect = tableView.rectForRowAtIndexPath(indexPath)
if indexPath.row == dataArray.count
{
dictionaryOfCellHeight[indexPath.row] = frame.size.height
//calculate total height and reload table
}
else
{
dictionaryOfCellHeight[indexPath.row] = frame.size.height
}
}
}
in Swift 3.0
let myRowHeight = yourTableView.rowHeight
To change the height of Tableview , you don't need to calculate the height of all UITableViewCells and set to TableView.
Set the height of each UITableViewCell properly in heightForRowAtIndexPath method. This will automatically set the scrollable height to your Tableview
You can use this
CGRect frame = [tableView rectForRowAtIndexPath:indexPath];
NSLog(#"row height : %f", frame.size.height);
Using frame.size.height you can get height of particular row
This is because self.tableView.contentSize.height returns number of rows * estimatedRowHeight, which is not equivalent to actual height of the table view. What you need is to get the individual cell heights through visibleCells, then sum those up to get the table view's height.
Refer to this for the answer:
https://stackoverflow.com/a/40081129/4076956
Maybe the table is not resizing its content, so if you try using [self. tableView layoutSubviews]; to force the resizing, it may work. [self. tableView layoutIfNeeded]; not necessarily forces the update.
Functionally (one-liner) 👌
NOTE: my section array stores the rows in the .data var
let heightOfAllRows:CGFloat = sections.enumerated().map { arg -> [(section:Int,row:Int)] in
return arg.element.data.indices.map{ i in
(section:arg.offset,row:i)
}
}.flatMap{$0}.reduce(0){
return $0 + self.tableView(self, heightForRowAt: .init(row: $1.row, section: $1.section))
}

Expand UITableViewCell when size of contents changes

I have a UITextView inside a static UITableViewCell constrained like this:
Picture
In the viewDidLoad() method of my table view class I want to be able to change the text of the UITextView, have the UITextView change size to fit the text (I have scrolling disabled on the UITextView), and then have the UITableViewCell still be constrained as I have intended it to be. This is my attempt to do so:
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.delegate = self
self.aboutTextView.text = "Some Long String"
//implement self sizing cells
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 400.0
//set the frame of the UITextView to match the size of the text
let fixedWidth = aboutTextView.frame.size.width
let newSize = aboutTextView.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat.max))
var newFrame = aboutTextView.frame
newFrame.size = CGSize(width: max(newSize.width, fixedWidth), height: newSize.height)
aboutTextView.frame = newFrame;
//This is returning the new size correctly
//Reload the tableview, nothing happens, text view remains the same size as in the storyboard
self.tableView.reloadData()
}
Although the new frame is bigger than the default size in the storyboard, nothing happens when the tableView is reloaded. I have tried setNeedsLayout() on the UITextView with no luck as well. I also tried constraining the height of the UITextView and changing the constant of the height through an IBOutlet but then the constraints break for obvious reasons. Anybody know why my code isn't working? Any better method to do what I am trying to do?
All the code about the row height should go in your tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) function. That way, whenever the table is reloaded, the code will be executed again, changing the table height.
Edit: I completely misunderstood what you were doing. In the storyboard, try adding constraints to the UITextView within the cell and give it a constraint on the height, and then make sure that the cell also has a height constraint slightly larger than that of the UITextView.

How do I set the height of tableHeaderView (UITableView) with autolayout?

I'm been smashing my head against the wall with this for last 3 or 4 hours and I can't seem to figure it out. I have a UIViewController with a full screen UITableView inside of it (there's some other stuff on the screen, which is why I can't use a UITableViewController) and I want to get my tableHeaderView to resize with autolayout. Needless to say, it's not cooperating.
See screenshot below.
Because the overviewLabel (e.g. the "List overview information here." text) has dynamic content, I'm using autolayout to resize it and it's superview. I've got everything resizing nicely, except for the tableHeaderView, which is right below Paralax Table View in the hiearchy.
The only way I've found to resize that header view is programatically, with the following code:
CGRect headerFrame = self.headerView.frame;
headerFrame.size.height = headerFrameHeight;
self.headerView.frame = headerFrame;
[self.listTableView setTableHeaderView:self.headerView];
In this case, headerFrameHeight is a manual calculation of the tableViewHeader height as follows (innerHeaderView is the white area, or the second "View", headerView is tableHeaderView):
CGFloat startingY = self.innerHeaderView.frame.origin.y + self.overviewLabel.frame.origin.y;
CGRect overviewSize = [self.overviewLabel.text
boundingRectWithSize:CGSizeMake(290.f, CGFLOAT_MAX)
options:NSStringDrawingUsesLineFragmentOrigin
attributes:#{NSFontAttributeName: self.overviewLabel.font}
context:nil];
CGFloat overviewHeight = overviewSize.size.height;
CGFloat overviewPadding = ([self.overviewLabel.text length] > 0) ? 10 : 0; // If there's no overviewText, eliminate the padding in the overall height.
CGFloat headerFrameHeight = ceilf(startingY + overviewHeight + overviewPadding + 21.f + 10.f);
The manual calculation works, but it's clunky and prone to error if things change in the future. What I want to be able to do is have the tableHeaderView auto-resize based on the provided constraints, like you can anywhere else. But for the life of me, I can't figure it out.
There's several posts on SO about this, but none are clear and ended up confusing me more. Here's a few:
Auto layout on UITableViewHeader
Auto Layout for tableHeaderView
Is it possible to use AutoLayout with UITableView's tableHeaderView?
table header view height is wrong when using auto layout, IB, and font sizes
It doesn't really make sense to change the translatesAutoresizingMaskIntoConstraints property to NO, since that just causes errors for me and doesn't make sense conceptually anyway.
Any help would really be appreciated!
EDIT 1:
Thanks to TomSwift's suggestion, I was able to figure it out. Instead of manually calculating the height of the overview, I can have it calculated for me as follows and then re-set the tableHeaderView as before.
[self.headerView setNeedsLayout];
[self.headerView layoutIfNeeded];
CGFloat height = [self.innerHeaderView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height + self.innerHeaderView.frame.origin.y; // adding the origin because innerHeaderView starts partway down headerView.
CGRect headerFrame = self.headerView.frame;
headerFrame.size.height = height;
self.headerView.frame = headerFrame;
[self.listTableView setTableHeaderView:self.headerView];
Edit 2: As others have noted, the solution posted in Edit 1 doesn't seem to work in viewDidLoad. It does, however, seem to work in viewWillLayoutSubviews. Example code below:
// Note 1: The variable names below don't match the variables above - this is intended to be a simplified "final" answer.
// Note 2: _headerView was previously assigned to tableViewHeader (in loadView in my case since I now do everything programatically).
// Note 3: autoLayout code can be setup programatically in updateViewConstraints.
- (void)viewWillLayoutSubviews {
[super viewWillLayoutSubviews];
[_headerWrapper setNeedsLayout];
[_headerWrapper layoutIfNeeded];
CGFloat height = [_headerWrapper systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
CGRect headerFrame = _headerWrapper.frame;
headerFrame.size.height = height;
_headerWrapper.frame = headerFrame;
_tableView.tableHeaderView = _headerWrapper;
}
You need to use the UIView systemLayoutSizeFittingSize: method to obtain the minimum bounding size of your header view.
I provide further discussion on using this API in this Q/A:
How to resize superview to fit all subviews with autolayout?
I've found an elegant way to way to use auto layout to resize table headers, with and without animation.
Simply add this to your View Controller.
func sizeHeaderToFit(tableView: UITableView) {
if let headerView = tableView.tableHeaderView {
let height = headerView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
var frame = headerView.frame
frame.size.height = height
headerView.frame = frame
tableView.tableHeaderView = headerView
headerView.setNeedsLayout()
headerView.layoutIfNeeded()
}
}
To resize according to a dynamically changing label:
#IBAction func addMoreText(sender: AnyObject) {
self.label.text = self.label.text! + "\nThis header can dynamically resize according to its contents."
}
override func viewDidLayoutSubviews() {
// viewDidLayoutSubviews is called when labels change.
super.viewDidLayoutSubviews()
sizeHeaderToFit(tableView)
}
To animate a resize according to a changes in a constraint:
#IBOutlet weak var makeThisTallerHeight: NSLayoutConstraint!
#IBAction func makeThisTaller(sender: AnyObject) {
UIView.animateWithDuration(0.3) {
self.tableView.beginUpdates()
self.makeThisTallerHeight.constant += 20
self.sizeHeaderToFit(self.tableView)
self.tableView.endUpdates()
}
}
See the AutoResizingHeader project to see this in action.
https://github.com/p-sun/Swift2-iOS9-UI
I really battled with this one and plonking the setup into viewDidLoad didn't work for me since the frame is not set in viewDidLoad, I also ended up with tons of messy warnings where the encapsulated auto layout height of the header was being reduced to 0. I only noticed the issue on iPad when presenting a tableView in a Form presentation.
What solved the issue for me was setting the tableViewHeader in viewWillLayoutSubviews rather than in viewDidLoad.
func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
if tableView.tableViewHeaderView == nil {
let header: MyHeaderView = MyHeaderView.createHeaderView()
header.setNeedsUpdateConstraints()
header.updateConstraintsIfNeeded()
header.frame = CGRectMake(0, 0, CGRectGetWidth(tableView.bounds), CGFloat.max)
var newFrame = header.frame
header.setNeedsLayout()
header.layoutIfNeeded()
let newSize = header.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)
newFrame.size.height = newSize.height
header.frame = newFrame
self.tableView.tableHeaderView = header
}
}
This solution resizes the tableHeaderView and avoids infinite loop in the viewDidLayoutSubviews() method I was having with some of the other answers here:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if let headerView = tableView.tableHeaderView {
let height = headerView.systemLayoutSizeFitting(UILayoutFittingCompressedSize).height
var headerFrame = headerView.frame
// comparison necessary to avoid infinite loop
if height != headerFrame.size.height {
headerFrame.size.height = height
headerView.frame = headerFrame
tableView.tableHeaderView = headerView
}
}
}
See also this post: https://stackoverflow.com/a/34689293/1245231
Your solution using systemLayoutSizeFittingSize: works if the header view is just updated once on each view appearance. In my case, the header view updated multiple times to reflect status changes. But systemLayoutSizeFittingSize: always reported the same size. That is, the size corresponding to the first update.
To get systemLayoutSizeFittingSize: to return the correct size after each update I had to first remove the table header view before updating it and re-adding it:
self.listTableView.tableHeaderView = nil;
[self.headerView removeFromSuperview];
This worked for me on ios10 and Xcode 8
func layoutTableHeaderView() {
guard let headerView = tableView.tableHeaderView else { return }
headerView.translatesAutoresizingMaskIntoConstraints = false
let headerWidth = headerView.bounds.size.width;
let temporaryWidthConstraints = NSLayoutConstraint.constraintsWithVisualFormat("[headerView(width)]", options: NSLayoutFormatOptions(rawValue: UInt(0)), metrics: ["width": headerWidth], views: ["headerView": headerView])
headerView.addConstraints(temporaryWidthConstraints)
headerView.setNeedsLayout()
headerView.layoutIfNeeded()
let headerSize = headerView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)
let height = headerSize.height
var frame = headerView.frame
frame.size.height = height
headerView.frame = frame
self.tableView.tableHeaderView = headerView
headerView.removeConstraints(temporaryWidthConstraints)
headerView.translatesAutoresizingMaskIntoConstraints = true
}
It works for both header view and footer just replace the header with footer
func sizeHeaderToFit() {
if let headerView = tableView.tableHeaderView {
headerView.setNeedsLayout()
headerView.layoutIfNeeded()
let height = headerView.systemLayoutSizeFitting(UILayoutFittingCompressedSize).height
var frame = headerView.frame
frame.size.height = height
headerView.frame = frame
tableView.tableHeaderView = headerView
}
}
For iOS 12 and above, the following steps will ensure autolayout works properly in both your table and the header.
Create your tableView first, then the header.
At the end of your header creation code, call:
[headerV setNeedsLayout];
[headerV layoutIfNeeded];
Upon orientation change, mark the header for layout again and reload the table, this needs to happen slightly after the orientation change is reported:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1 *NSEC_PER_SEC), dispatch_get_main_queue(), ^{
[tableV.tableHeaderView setNeedsLayout];
[tableV.tableHeaderView layoutIfNeeded];
[tableV reloadData];});
In my case viewDidLayoutSubviews worked better. viewWillLayoutSubviews causes white lines of a tableView to appear. Also I added checking if my headerView object already exists.
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
if ( ! self.userHeaderView ) {
// Setup HeaderView
self.userHeaderView = [[[NSBundle mainBundle] loadNibNamed:#"SSUserHeaderView" owner:self options:nil] objectAtIndex:0];
[self.userHeaderView setNeedsLayout];
[self.userHeaderView layoutIfNeeded];
CGFloat height = [self.userHeaderView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
CGRect headerFrame = self.userHeaderView.frame;
headerFrame.size.height = height;
self.userHeaderView.frame = headerFrame;
self.tableView.tableHeaderView = self.userHeaderView;
// Update HeaderView with data
[self.userHeaderView updateWithProfileData];
}
}
It is quite possible to use generic AutoLayout-based UIView with any AL inner subview structure as a tableHeaderView.
The only thing one needs is to set a simple tableFooterView before!
Let self.headerView is some constraint-based UIView.
- (void)viewDidLoad {
........................
self.tableView.tableFooterView = [UIView new];
[self.headerView layoutIfNeeded]; // to set initial size
self.tableView.tableHeaderView = self.headerView;
[self.tableView.leadingAnchor constraintEqualToAnchor:self.headerView.leadingAnchor].active = YES;
[self.tableView.trailingAnchor constraintEqualToAnchor:self.headerView.trailingAnchor].active = YES;
[self.tableView.topAnchor constraintEqualToAnchor:self.headerView.topAnchor].active = YES;
// and the key constraint
[self.tableFooterView.trailingAnchor constraintEqualToAnchor:self.headerView.trailingAnchor].active = YES;
}
If self.headerView changes height under UI rotation one have to implement
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
[coordinator animateAlongsideTransition: ^(id<UIViewControllerTransitionCoordinatorContext> context) {
// needed to resize header height
self.tableView.tableHeaderView = self.headerView;
} completion: NULL];
}
One can use ObjC category for this purpose
#interface UITableView (AMHeaderView)
- (void)am_insertHeaderView:(UIView *)headerView;
#end
#implementation UITableView (AMHeaderView)
- (void)am_insertHeaderView:(UIView *)headerView {
NSAssert(self.tableFooterView, #"Need to define tableFooterView first!");
[headerView layoutIfNeeded];
self.tableHeaderView = headerView;
[self.leadingAnchor constraintEqualToAnchor:headerView.leadingAnchor].active = YES;
[self.trailingAnchor constraintEqualToAnchor:headerView.trailingAnchor].active = YES;
[self.topAnchor constraintEqualToAnchor:headerView.topAnchor].active = YES;
[self.tableFooterView.trailingAnchor constraintEqualToAnchor:headerView.trailingAnchor].active = YES;
}
#end
And also Swift extension
extension UITableView {
func am_insertHeaderView2(_ headerView: UIView) {
assert(tableFooterView != nil, "Need to define tableFooterView first!")
headerView.layoutIfNeeded()
tableHeaderView = headerView
leadingAnchor.constraint(equalTo: headerView.leadingAnchor).isActive = true
trailingAnchor.constraint(equalTo: headerView.trailingAnchor).isActive = true
topAnchor.constraint(equalTo: headerView.topAnchor).isActive = true
tableFooterView?.trailingAnchor.constraint(equalTo: headerView.trailingAnchor).isActive = true
}
}
This solution works perfectly for me:
https://spin.atomicobject.com/2017/08/11/swift-extending-uitableviewcontroller/
It extends the UITableViewController. But if you are just using a UITableView, it will still work, just extend the UITableView instead of the UITableViewController.
Call the methods sizeHeaderToFit() or sizeFooterToFit() whenever there is an event that changes the tableViewHeader height.
Copied from this post
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if let headerView = tableView.tableHeaderView {
let height = headerView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize).height
var headerFrame = headerView.frame
//Comparison necessary to avoid infinite loop
if height != headerFrame.size.height {
headerFrame.size.height = height
headerView.frame = headerFrame
tableView.tableHeaderView = headerView
}
}
}

Resources