I have problem with UILabel in UITableView. I want to bring film's plot in UILabel, but when application started, I have just one line of non-full plot, but when I scroll down and up, I get full film's plot with 2-3 lines. What problem can be?
In UILabel preferences I choose 0 lines (It makes label is multiline).
In ViewController, in "viewDidLoad" I wrote two line of code, to make cell resizable:
self.searchTableView.estimatedRowHeight = 44.0
self.searchTableView.rowHeight = UITableViewAutomaticDimension
Call [view layoutIfNeeded] after set the text of UILabel. It will layout subviews again.
With UILabel over multiple lines, you have to give it a hand to know when to wrap text during layout.
To do this you need to set the preferredMaxLayoutWidth property. See https://developer.apple.com/library/ios/documentation/UIKit/Reference/UILabel_Class/#//apple_ref/occ/instp/UILabel/preferredMaxLayoutWidth
So in your cellForRowAtIndexPath method add something like:
cell.yourUILabelIBOutlet.preferredMaxLayoutWidth = tableView.frame.size.width;
You can do this using autolayout in UITableViewCell. it's working for me.
Add UILabel in your tableview
Set UILabel Leading,Trailling,top and bottom constraints.(Note : don't set height for that label)
Then set UILabel NO.Of line 0 and set Line Break mode.
Set your tableview cell height
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
tableView.estimatedRowHeight = 150
return UITableViewAutomaticDimension
}
Add the below code and try it. It works##
-(void)viewDidLoad {
[super viewDidLoad];
//at last line of viewDidLoad
[self performSelector:#selector(reloadtable) withObject:nil afterDelay:1.0];
}
-(void)reloadtable
{
[self.tableView reloadData];
}
Related
What I want is my UITableViewCell to expand/shrink based on the height of the UILabel inside.
I have tried just about every solution I could find and it's not working. Maybe I have some setting that's preventing it.
Here is a screenshot of the UITableViewCell settings:
For the UILabel inside, Lines is set to 0 and Line Break to Word Wrap.
In the UIViewController where I'm showing the table view, I am setting this in viewDidLoad():
tableView.rowHeight = UITableView.automaticDimension
tableView.estimatedRowHeight = 44
tableView.reloadData()
And in cellForRowAt after dequeuing the cell I'm doing (instructionText being the UILabel):
cell.instructionText.numberOfLines = 0
I've seen this in many tutorials and it works, why not for these cells? The content comes out like this:
This is driving me crazy! Thanks for any help!
EDIT: Here are the UILabel settings:
Please check your label constraints
I want to increase tableview cell and tableview height based on content.
Suppose tableview contain 2 record and his 1st cell height is 100 and 2nd cell height is 25 then tableview height should be 100+25=125.
How to achieve this functionality?
Thanks in advance.
You can definitely do that,
First make sure your constraint of cells subView must set to top to bottom in order to calculate the height required for the cell.
Make sure your delegated are set as below
-(CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 44;
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return UITableViewAutomaticDimension;
}
Set height constraint of your tableView and make outlet of that constraint.
Add below method to your class where you want to resize your tableView dynamically.
- (void)adjustHeightOfTableview
{
CGFloat height = self.tableView.contentSize.height;
//CGFloat maxHeight = self.tableView.superview.frame.size.height - self.tableView.frame.origin.y;
/*
Here you have to take care of two things, if there is only tableView on the screen then you have to see is your tableView going below screen using maxHeight and your screen height,
Or you can add your tableView inside scrollView so that your tableView can increase its height as much it requires based on the number of cell (with different height based on content) it has to display.
*/
// now set the height constraint accordingly
self.constraintHeightTableView.constant = height;
//If you want to increase tableView height with animation you can do that as below.
[UIView animateWithDuration:0.5 animations:^{
[self.view layoutIfNeeded];
}];
}
Call this method when you are ready with the dataSource for the table, and call the method as
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
//In my case i had to call this method after some delay, because (i think) it will allow tableView to reload completely and then calculate the height required for itself. (This might be a workaround, but it worked for me)
[self performSelector:#selector(adjustHeightOfTableview) withObject:nil afterDelay:0.3];
});
If you are running iOS 8+,
You can use:
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 80 // your desired or expected height
properties.
for this to take effect you should not have any height set in heightForRowAtIndexpath
You should set the cell constraints i.e., constraints for the elements present inside cell, so the set constraints are enough for the tableviewcell to calculate it's height in run time
Solution in swift 3
Step 1.
Set the top, bottom, leading and trailing constraints (do not make it constant height, but do set a constant height constraint as of now).
Now we gonna change this height dynamically based on the number of cells and its height.
Step 2.
Drag an outlet of that height constraint to the class, and copy this function anywhere in the class.
func adjustHeightOfTableview() {
let height: CGFloat = tableview.contentSize.height
self.outLetOfTheHeightConstraint.constant = height
}
Step 3.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
DispatchQueue.main.async {
self.tableview.reloadData()
self.perform(#selector(self.adjustHeightOfTableview))
}
}
self.tableView.frame = CGRectMake(self.tableView.origin.x, self.tableView.origin.y, self.tableView.frame.size.width, 125);
I have an UITableViewController that contains a custom cell. Each cell was created using a nib and contains a single non-scrollable UITextView. I have added constraints inside each cell so that the cell adapts its height to the content of the UITextView. So initially my controller looks like this :
Now I want that when the user types something in a cell its content automatically adapts. This question has been asked many times, see in particular this or the second answer here. I have thus written the following delegate in my code :
- (BOOL) textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString*)text {
[self.tableView beginUpdates];
[self.tableView endUpdates];
return YES;
}
However it leads to the following strange behavior : all constraints are ignored and all cells height collapse to the minimal value. See the picture below:
If I scroll down and up the tableView in order to force for a new call of cellForRowAtIndexPath, I recover the correct heights for the cells:
Note that I did not implement heightForRowAtIndexPath as I expect autoLayout to take care of this.
Could someone tell me what I did wrong or help me out here ? Thank you very much !
Here is a swift solution that is working fine for me. Provided you are using auto layout, you need assign a value to estimatedRowHeight and then return UITableViewAutomaticDimension for the row height. Finally do something similar to below in the text view delegate.
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.estimatedRowHeight = 44.0
}
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
// MARK: UITextViewDelegate
func textViewDidChange(textView: UITextView) {
// Calculate if the text view will change height, then only force
// the table to update if it does. Also disable animations to
// prevent "jankiness".
let startHeight = textView.frame.size.height
let calcHeight = textView.sizeThatFits(textView.frame.size).height //iOS 8+ only
if startHeight != calcHeight {
UIView.setAnimationsEnabled(false) // Disable animations
self.tableView.beginUpdates()
self.tableView.endUpdates()
// Might need to insert additional stuff here if scrolls
// table in an unexpected way. This scrolls to the bottom
// of the table. (Though you might need something more
// complicated if editing in the middle.)
let scrollTo = self.tableView.contentSize.height - self.tableView.frame.size.height
self.tableView.setContentOffset(CGPoint(x: 0, y: scrollTo), animated: false)
UIView.setAnimationsEnabled(true) // Re-enable animations.
}
My solution is similar to #atlwx but a bit shorter. Tested with static table. UIView.setAnimationsEnabled(false) is needed to prevent cell's contents "jumping" while table updates that cell's height
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.estimatedRowHeight = 44.0
}
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func textViewDidChange(_ textView: UITextView) {
UIView.setAnimationsEnabled(false)
textView.sizeToFit()
self.tableView.beginUpdates()
self.tableView.endUpdates()
UIView.setAnimationsEnabled(true)
}
Tested on iOS 12
I really tried a lot of solutions and finally found a good one here
This works with animation and looks beautiful. The trick was the DispatchQueue.async block.
I also used TPKeyboardAvoidingTableView to make sure the keyboard doesn't overlap anything.
func textViewDidChange(_ textView: UITextView) {
// Animated height update
DispatchQueue.main.async {
self.tableView?.beginUpdates()
self.tableView?.endUpdates()
}
}
UPDATE
I got strange jumping issues because of TPKeyboardAvoidingTableView. Especially when I scrolled to the bottom and then a UITextView got active.
So I replaced TPKeyboardAvoidingTableView by native UITableView and handle the insets myself. The table view is does the scrolling natively.
The following example works for dynamic row height as the user types text into the cell. Even if you use auto layout you still have to implement the heightForRowAtIndexPath method. For this example to work constraints must be set to textView in such a way that if cell height increases textView will also grow in height. This can be achieved by adding a top constraint and bottom constraint from textView to cell content view. But do not set height constraint for textView itself. Also enable scrolling for the textView so that textView's content size will be updated as the user enters text. Then we use this content size to calculate the new row height. As long as the row height is long enough to vertically stretch the textView to equal to or greater than its content size the text view will not scroll even if scroll is enabled and that is what you need I believe.
In this example I have only a single row and I use only a single variable to keep track of the row height. But when we have multiple rows we need a variable for each row otherwise all the rows will have the same height. An array of rowHeight that corresponds to the tableView data source array may be used in that case.
#interface ViewController ()
#property (nonatomic, assign)CGFloat rowHeight;;
#property (weak, nonatomic) IBOutlet UITableView *tableView;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.rowHeight = 60;
}
#pragma mark - UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell1"];
return cell;
}
#pragma mark - UITableViewDelegate
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return self.rowHeight;
}
#pragma mark - UITextViewDelegate
- (void)textViewDidChange:(UITextView *)textView {
[self.tableView beginUpdates];
CGFloat paddingForTextView = 40; //Padding varies depending on your cell design
self.rowHeight = textView.contentSize.height + paddingForTextView;
[self.tableView endUpdates];
}
#end
Using Swift 2.2 (earlier versions would likely work too), if you set the TableView to use auto dimensions (assuming you're working in a subclassed UITableViewController, like so:
self.tableView.rowHeight = UITableViewAutomaticDimension
self.tableView.estimatedRowHeight = 50 // or something
You just need to implement the delegate in this file, UITextViewDelegate, and add the below function, and it should work. Just remember to set your textView's delegate to self (so, perhaps after you've dequeued the cell, cell.myTextView.delegate = self)
func textViewDidChange(textView: UITextView) {
self.tableView.beginUpdates()
textView.frame = CGRectMake(textView.frame.minX, textView.frame.minY, textView.frame.width, textView.contentSize.height + 40)
self.tableView.endUpdates()
}
Thanks to "Jose Tomy Joseph" for inspiring (enabling, really) this answer.
I've implemented a similar approach using a UITextView however to do so I had to implement heightForRowAtIndexPath
#pragma mark - SizingCell
- (USNTextViewTableViewCell *)sizingCell
{
if (!_sizingCell)
{
_sizingCell = [[USNTextViewTableViewCell alloc] initWithFrame:CGRectMake(0.0f,
0.0f,
self.tableView.frame.size.width,
0.0f)];
}
return _sizingCell;
}
#pragma mark - UITableViewDelegate
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
self.sizingCell.textView.text = self.profileUpdate.bio;
[self.sizingCell setNeedsUpdateConstraints];
[self.sizingCell updateConstraintsIfNeeded];
[self.sizingCell setNeedsLayout];
[self.sizingCell layoutIfNeeded];
CGSize cellSize = [self.sizingCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
return cellSize.height;
}
sizingCell is an instance of the cell that is only used for sizing calculations.
What's important to note is that you need to attach the UITextView's upper and lower edge to the UITableViewCells contentView's upper and lower edge so that as the UITableViewCell changes in height the UITextView also changes in height.
For constraint layout I use a PureLayout (https://github.com/smileyborg/PureLayout) so the following constraint layout code may be unusual for you:
#pragma mark - Init
- (id)initWithStyle:(UITableViewCellStyle)style
reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style
reuseIdentifier:reuseIdentifier];
if (self)
{
[self.contentView addSubview:self.textView];
}
return self;
}
#pragma mark - AutoLayout
- (void)updateConstraints
{
[super updateConstraints];
/*-------------*/
[self.textView autoPinEdgeToSuperviewEdge:ALEdgeLeft
withInset:10.0f];
[self.textView autoPinEdgeToSuperviewEdge:ALEdgeTop
withInset:5.0f];
[self.textView autoPinEdgeToSuperviewEdge:ALEdgeBottom
withInset:5.0f];
[self.textView autoSetDimension:ALDimensionWidth
toSize:200.0f];
}
Inspired by the two previous answers, I found a way to solve my problem. I think the fact that I had a UITextView was causing some troubles with autoLayout. I added the following two functions to my original code.
- (CGFloat)textViewHeightForAttributedText: (NSAttributedString*)text andWidth: (CGFloat)width {
UITextView *calculationView = [[UITextView alloc] init];
[calculationView setAttributedText:text];
CGSize size = [calculationView sizeThatFits:CGSizeMake(width, FLT_MAX)];
return size.height;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
UIFont *font = [UIFont systemFontOfSize:14.0];
NSDictionary *attrsDictionary = [NSDictionary dictionaryWithObject:font forKey:NSFontAttributeName];
NSAttributedString *attrString = [[NSAttributedString alloc] initWithString:self.sampleStrings[indexPath.row] attributes:attrsDictionary];
return [self textViewHeightForAttributedText:attrString andWidth:CGRectGetWidth(self.tableView.bounds)-31]+20;
}
where in the last line 31 is the sum of my constraints to the left and right sides of the cell and 20 is just some arbitrary slack.
I found this solution while reading this this very interesting answer.
The trick to immediately update the tableview cells height in a smooth way without dismissing the keyboard is to run the following snippet to be called in the textViewDidChange event after you set the size of the textView or other contents you have in the cell:
[tableView beginUpdates];
[tableView endUpdates];
However this will may not be enough. You should also make sure the tableView has enough elasticity to keep the same contentOffset. You get that elasticity by setting the tableView contentInset bottom. I suggest this elasticity value to be at least the maximum distance you need from the bottom of the last cell to the bottom of the tableView. For instance, it could be the height of the keyboard.
self.tableView.contentInset = UIEdgeInsetsMake(0, 0, keyboardHeight, 0);
For more details and some useful extra features around this matter please check out the following link:
Resize and move UITableViewCell smoothly without dismissing keyboard
The solution almost everyone suggested is the way to go, I will add only a minor improvement. As a recap:
Simply set the estimated height, I do it via storyboard:
Make sure you have the constraints for the UITextView correctly set within the cell.
In the func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
I simply call:
cell.myTextView.sizeToFit()
Previously beginUpdates/endUpdates were the advertised solution.
Since iOS 11, performBatchUpdates is what has been recommended source.
Calling performBatchUpdates after making a change to a cell's content works for me.
Check out the Objective C solution I have provided in the following link below.
Simple to implement, clean, and no need for auto layout. No constraints needed. Tested in iOS10 and iOS11.
Resize and move UITableViewCell smoothly without dismissing keyboard
Hi there is plenty of question answering the dynamic height for UITableViewCell of UITableView. However I find it weird when I did it.
here's are some of the answer :
here and here
usually this would answer the dynamic height for cell
tableView.estimatedRowHeight = 44.0
tableView.rowHeight = UITableView.automaticDimension
but in my case I wonder this line wont do anything.
my UITableView is being viewed after clicking tabbar inside the splitview. Is this helpful?
Maybe I'm Missing something. Could anyone help me I spent 2 hours doing silly.
These are my constraint for title the title could be long but the label is not.
and this is my cell
In order to make UITableViewAutomaticDimension work you have to set all left, right, bottom, and top constraints relative to cell container view. In your case you will need to add the missing bottom space to superview constraint for label under the title
I had added constraints programmatically, and accidentally added them to the cell directly, i.e. not on the contentView property. Adding the constraints to contentView resolved it for me!
To set automatic dimension for row height & estimated row height, ensure following steps to make, auto dimension effective for cell/row height layout.
Assign and implement tableview dataSource and delegate
Assign UITableViewAutomaticDimension to rowHeight & estimatedRowHeight
Implement delegate/dataSource methods (i.e. heightForRowAt and return a value UITableViewAutomaticDimension to it)
-
Objective C:
// in ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
#property IBOutlet UITableView * table;
#end
// in ViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
self.table.dataSource = self;
self.table.delegate = self;
self.table.rowHeight = UITableViewAutomaticDimension;
self.table.estimatedRowHeight = UITableViewAutomaticDimension;
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return UITableViewAutomaticDimension;
}
Swift:
#IBOutlet weak var table: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Don't forget to set dataSource and delegate for table
table.dataSource = self
table.delegate = self
// Set automatic dimensions for row height
// Swift 4.2 onwards
table.rowHeight = UITableView.automaticDimension
table.estimatedRowHeight = UITableView.automaticDimension
// Swift 4.1 and below
table.rowHeight = UITableViewAutomaticDimension
table.estimatedRowHeight = UITableViewAutomaticDimension
}
// UITableViewAutomaticDimension calculates height of label contents/text
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
// Swift 4.2 onwards
return UITableView.automaticDimension
// Swift 4.1 and below
return UITableViewAutomaticDimension
}
For label instance in UITableviewCell
Set number of lines = 0 (& line break mode = truncate tail)
Set all constraints (top, bottom, right left) with respect to its superview/ cell container.
Optional: Set minimum height for label, if you want minimum vertical area covered by label, even if there is no data.
Note: If you've more than one labels (UIElements) with dynamic length, which should be adjusted according to its content size: Adjust 'Content Hugging and Compression Resistance Priority` for labels which you want to expand/compress with higher priority.
Also make sure the Lines for your UILabel in the cell is set to 0. If it is set to 1, it will not grow vertically.
I have a specific case, and 99% of the solutions I read didn't work. I thought I'd share my experience. Hope it can helps, as I'd struggled for a couple of hours before fixing this issue.
My scenario:
I'm using two TableViews in one ViewController
I am loading Custom Cells (xib) in those tableviews
Dynamic content in cells consists of two labels
Page uses a ScrollView
What I needed to achieve:
Dynamic TableView height
Dynamic TableViewCells height
What you'll need to check to make it work smoothly:
Like every tutorial and answer will tell you, set all the constraints for your label/content (top, bottom, leading & trailing), and set it to the ContentView (Superview). This video tutorial will be helpful.
In the viewWillAppear method of my ViewController, I am giving one of my tableViews (tableView2) an estimated row height and then use the UITableViewAutomaticDimension as such (and as seen in all tutorials/answers):
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
tableView2.estimatedRowHeight = 80
tableView2.rowHeight = UITableViewAutomaticDimension
}
For me, these previous steps were not enough. My TableView would simply take the estimatedRowHeight and multiply it by the number of cells. Meeeh.
As I am using two different tableViews, I created an outlet for each of them, tableView1 and tableView2. Allowing me to resize them in the viewDidLayoutSubviews method. Feel free to ask in comment how I did this.
One additional step fixed it for me, by adding this to the viewDidAppear method:
override func viewDidAppear(_ animated: Bool) {
tableView1.reloadData() // reloading data for the first tableView serves another purpose, not exactly related to this question.
tableView2.setNeedsLayout()
tableView2.layoutIfNeeded()
tableView2.reloadData()
}
Hope that helps someone!
As of iOS 11 and Xcode 9.3, most of the above information is wrong. Apple's Guide suggests setting
tableView.estimatedRowHeight = 85.0
tableView.rowHeight = UITableViewAutomaticDimension
WWDC 2017 session 245 (Building Apps with Dynamic Type, about 16:33 into the video) suggests something similar. None of this made a difference for me.
For a Subtitle style cell, all that's necessary to get self-sizing table view cells is to set the number of lines (in the Label section of the attributes inspector) to 0 for both the Title and Subtitle. If one of these labels is too long and you don't set the number of lines to 0, the table view cell won't adjust its size.
Forgot to remove tableView(heightForRowAt:indexPath:)
It could be the case that, like me, you accidentally forgot to remove the boilerplate code for the heightForRowAt method.
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 60.0
}
For anyone that maybe faced the same problem with me: I struggled for an hour to make it work. A simple UIlabel with top, bottom left and right constraints. I used the willDisplayCell to pass the data to the cell and this was causing problems in cells height. As long as I put that code in cellForRow everything worked just fine. Didn't understand why this happened, maybe the cell height was calculated before willDisplayCell was called so there was no content to make the right calculation. I was just wanted to mention and probably help someone with the same problem.
it was working for me fine in iOS 11 and above, while breaking in iOS 10
the solution was to add
table.rowHeight = UITableView.automaticDimension
table.estimatedRowHeight = 200 // a number and not UITableView.automaticDimension
also make sure you add "heightForRowAt" even if it works in iOS 11 and above, its needed if you support iOS 10
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
In my case i had two UITableViews, i had to modify this method as
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
CGFloat height = 0.0;
if (tableView == self.tableviewComments) {
return UITableViewAutomaticDimension;
}else if (tableView == self.tableViewFriends) {
height = 44.0;
}
return height;
}
Try this, Simple solution it's work for me,
In viewDidLoad write this code,
-(void)viewDidLoad
{
[super viewDidLoad];
self.tableView.estimatedRowHeight = 100.0; // for example. Set your average height
self.tableView.rowHeight = UITableViewAutomaticDimension;
}
In cellForRowAtIndexPath write this code,
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] ;
}
cell.textLabel.numberOfLines = 0; // Set label number of line to 0
cell.textLabel.text=[[self.arForTable objectAtIndex:indexPath.row] valueForKey:#"menu"];
[cell.textLabel sizeToFit]; //set size to fit
return cell;
}
For my setup, I first double checked the constraints in the Storyboard for the UITableViewCell were unambiguous top to bottom, and then had to modify code in 2 places.
UITableViewDelegate's tableView(_:heightForRowAt:)
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
// return UITableViewAutomaticDimension for older than Swift 4.2
}
UITableViewDelegate's tableView(_:estimatedHeightForRowAt:)
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
// return UITableViewAutomaticDimension for older than Swift 4.2
}
Step 1 and 2, lets you to apply autosizing just for particular rows. For applying to the whole UITableView, use:
tableView.rowHeight = UITableView.automaticDimension
tableView.estimatedRowHeight = UITableView.automaticDimension
// return UITableViewAutomaticDimension for older than Swift 4.2
An uncommon solution, but one that may save others time: in cellForRowAtIndexPath make sure there is no delay in setting your label text. For some unknown reason, I had it wrapped in a DispatchQueue.main.async block, and this meant that the cell was being returned before the label text was actually set, so the cell and label never expanded to the size of the text.
In order to make UITableViewAutomaticDimension to work, you need to make sure all 4 corners' constraints is added to the superview. In most case, it works well with UILabel, but sometimes i find UITextView does the trick when UILabel not working well at the time. So try to switch to UITextView and make sure Scrolling Enabled is unchecked in storyboard, or you can also set it programmatically.
I had three horizontal items and the most left had a constraint to left, middle one had top, bottom, to the left item and to the right item. The right one had a right, and left to the middle item. The solution was to add additional left and right constraints to the middle item (my label) that were >= some number to the cell.
Make sure all views in the cell are constrained to the Content View and not to the cell.
As apple says:
lay out the table view cell’s content within the cell’s content view. To define the cell’s height, you need an unbroken chain of constraints and views (with defined heights) to fill the area between the content view’s top edge and its bottom edge.
In my case I did everything but it did not solve the problem for me, at last, I checked the lines of the label which was fixed to 3. Changing the line value to 0 solves the problem for me. so to tell you all it must be 0 and constraints Top, Bottom, Left, Right must be attached to work fine.
For recent version of ios and swift apple has changed the previously called UITableView.automaticDimension to UITableView().estimatedRowHeight, so to set the row height automatically use it like this:
tableView.estimatedRowHeight = 150 //random estimate manually to help the compiler before setting the estimate value.
tableView.rowHeight = UITableView().estimatedRowHeight
I've got a new solution..that's worked for me.
basically UITableViewAutomaticDimension renamed as UITableView.automaticDimension... I hope..it wo
I'm working on an app where I face a strange issue. I've created a UITableViewController in the storyboard and added a prototype cell. In this cell, I've added an UILabel element and this UILabel takes up the whole cell. I've set it up with Auto Layout and added left, right, top and bottom constraints. The UILabel contains some text.
Now in my code, I initialize the the rowHeight and estimatedRowHeight of the table view:
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.rowHeight = UITableViewAutomaticDimension
self.tableView.estimatedRowHeight = 50
}
And I create the cell as follows:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell : UITableViewCell? = tableView.dequeueReusableCellWithIdentifier("HelpCell") as? UITableViewCell
if(cell == nil) {
cell = UITableViewCell(style: .Default, reuseIdentifier: "HelpCell")
}
return cell!
}
I return two rows in my table view. Here comes my problem: the height of the first row is way to large. It appear that the second, third row etc all have a correct height. I really don't understand why this is the case. Can someone help me with this?
I had a problem where the cells' height were not correct on the first load, but after scrolling up-and-down the cells' height were fixed.
I tried all of the different 'fixes' for this problem and then eventually found that calling these functions after initially calling self.tableView.reloadData.
self.tableView.reloadData()
// Bug in 8.0+ where need to call the following three methods in order to get the tableView to correctly size the tableViewCells on the initial load.
self.tableView.setNeedsLayout()
self.tableView.layoutIfNeeded()
self.tableView.reloadData()
Only do these extra layout calls after the initial load.
I found this very helpful information here: https://github.com/smileyborg/TableViewCellWithAutoLayoutiOS8/issues/10
Update:
Sometimes you might have to also completely configure your cell in heightForRowAtIndexPath and then return the calculated cell height. Check out this link for a good example of that, http://www.raywenderlich.com/73602/dynamic-table-view-cell-height-auto-layout , specifically the part on heightForRowAtIndexPath.
Update 2: I've also found it VERY beneficial to override estimatedHeightForRowAtIndexPath and supply somewhat accurate row height estimates. This is very helpful if you have a UITableView with cells that can be all kinds of different heights.
Here's a contrived sample implementation of estimatedHeightForRowAtIndexPath:
public override func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
let cell = tableView.cellForRowAtIndexPath(indexPath) as! MyCell
switch cell.type {
case .Small:
return kSmallHeight
case .Medium:
return kMediumHeight
case .Large:
return kLargeHeight
default:
break
}
return UITableViewAutomaticDimension
}
Update 3: UITableViewAutomaticDimension has been fixed for iOS 9 (woo-hoo!). So you're cells should automatically size themselves without having to calculate the cells height manually.
As the Apple says in the description of setNeedsLayout:
This method does not force an immediate update, but instead waits for the next update cycle, you can use it to invalidate the layout of multiple views before any of those views are updated. This behavior allows you to consolidate all of your layout updates to one update cycle, which is usually better for performance.
Because of this you should add needed lines of code (which should be executed with right layout) in dispatch_after block(which will put your method in queue of RunLoop). And your code will be executed after needs layout applies.
Example:
- (void)someMethod {
[self.tableView reloadData];
[self.tableView setNeedsLayout];
[self.tableView layoutIfNeeded];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
//code which should be executed with the right size of table
});
In iOS 8, assigning the estimatedRowHeight a value turns on the new iOS 8 automatic row height calculation feature. This means that the cell's height is derived by using its internal constraints from the inside out. If there's something wrong with those constraints you'll get odd results. So there's something wrong with your cell constraints. They are probably ambiguous; that is the usual reason for inconsistency. However that's all I can tell you, since you have not actually shown / described the constraints.
I suggest removing the bottom constraint on the UILabel. It will resize according to the text and the cell should resize as well.
If that didn't resolve the issue, try adding the following in viewDidLoad() :
self.tableView.reloadData()
This worked for me
- (void)layoutSubviews
{
[super layoutSubviews];
// Your implementation
}
I got this from here >> http://askstop.com/questions/2572338/uitableview-displays-separator-at-wrong-position-in-ios8-for-some-cells