Dynamic cell height iOS - ios

I'm trying to dynamically recalculate the height of the cell that contain UITextView. The height of the cell depends on the height UITextView.
The source code below recalculate height for each cell in table. This is the some text from NSDictionary. After all heights has recalculated I reload my table view with new height that contain in array heightCells;
UITextView *tempTextView = [[UITextView alloc] init];
UIFont *font = [UIFont fontWithName:#"Helvetica" size:16.0];
[tempTextView setFrame:CGRectMake(10, 63, 300, 9999)];
[tempTextView setFont:font];
NSString *str = [d valueForKey:#"definition"]; // set long text
tempTextView.text = str;
CGRect frame = tempTextView.frame;
frame.size.height = tempTextView.contentSize.height + 20.0;
tempTextView.frame = frame;
[tempTextView sizeToFit];
int height = tempTextView.frame.size.height + 150.0; // set padding 150.0 px
[heightCells addObject:[NSNumber numberWithFloat:height]];
UITableView method:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return [[heightCells objectAtIndex:indexPath.row] floatValue];
}
On not retina display everything work good and the height recalculated correct, but on retina display I have problem with recalculation. I know that the retina and not retina have one 320x480 points view and it should not affect for recalculation. But in my case this is appear.
Please see screenshot below. As you can see on screenshot the bottom padding after share button a different for retina and not retina display. And I don't know which kind this problem.
Thanks for help!

It seems the tempTextView's frame differs when it is on the UITableViewCell. I described my working technique in this answer.

Related

How to change the height of a custom cell individually within a UITableView?

I am trying to change the height of each cell individually based on how long my UILabel is, but it does not seem to change.
I have found the following question: How to change cell height dynamically in UITableView static cell
I tried the solution from that question:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
//return 110;
NewsFlashCustomCell *cell;
static NSString *CellIdentifier = #"CustomCell";
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
[cell layoutIfNeeded];
return cell.messageLabel.frame.origin.y + cell.messageLabel.frame.size.height;
}
However, that seems to do nothing.
Here's a screenshot:
I'd like the height of the cells containing "tidal wave" and "mashup" to be smaller than the last 2 cells since it has a longer message.
I cannot perform a indexPath.row check to change each cell individually because each message is pulled from a database, so the length of the message varies.
What can be done?
In case it helps, here's a screenshot of my constraints:
Thanks.
UPDATE:
I added the following code in viewDidLoad:
tableView.rowHeight = UITableViewAutomaticDimension;
This is what it looks like:
If you can't set try with other method reduce the label font size depend upon the cell height .
label.numberOfLines=0;
label.clipsToBounds=YES;
label.adjustsFontSizeToFitWidth=YES;
label.lineBreakMode = NSLineBreakByWordWrapping;
You can calculate height for label from its length of text and do it like following way:
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
return [self calculateHeightForCellAtIndexPath:indexPath];
}
#pragma mark - cell height handling
-(CGFloat)calculateHeightForCellAtIndexPath:(NSIndexPath *)indexP{
UILabel *lbl = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, self.tableView.frame.size.width-22, defaultHeightOfYourLabel)];
NSString *strLbl;
strLbl = [yourArray objectAtIndex:indexP.row];
lbl.text = strLbl;
if (IS_IPAD) {
[lbl setFont:fontRegular15];
}else{
[lbl setFont:fontRegular12];
}
UIFontDescriptor * fontDLBLTime = [lbl.font.fontDescriptor
fontDescriptorWithSymbolicTraits:UIFontDescriptorTraitBold];
if (IS_IPAD) {
[lbl setFont:[UIFont fontWithDescriptor:fontDLBLTime size:15]];
}else{
[lbl setFont:[UIFont fontWithDescriptor:fontDLBLTime size:12]];
}
[lbl setLineBreakMode:NSLineBreakByClipping];
[lbl setNumberOfLines:0];
int noOfLines = [GlobalFunction lineCountForLabel:lbl];
CGFloat height = [GlobalFunction heightForWidth:lbl.frame.size.width usingFont:lbl.font forLabel:lbl];
if (noOfLines>1) {
return height + 33; //here 33 is sum of top and bottom space from view.
}
return 50; //default height of cell.
}
In your class implement following methods:
#define CGFLOAT_MAX_HEIGHT 2000.0
+ (int)lineCountForLabel:(UILabel *)label {
return ceil([self heightForWidth:label.frame.size.width usingFont:label.font forLabel:label] / label.font.lineHeight);
}
+(CGFloat)heightForWidth:(CGFloat)width usingFont:(UIFont *)font forLabel:(UILabel *)lbl{
NSStringDrawingContext *context = [[NSStringDrawingContext alloc] init];
CGSize labelSize = (CGSize){width, CGFLOAT_MAX_HEIGHT};
CGRect r = [lbl.text boundingRectWithSize:labelSize options:NSStringDrawingUsesLineFragmentOrigin attributes:#{NSFontAttributeName: font} context:context];
return r.size.height;
}
You can customize lbl on basis of your font and label size.
Have your label constrain the bounds of your cell, like your already doing. Be sure to include padding around it so it looks nicer.
In your heightForRowAtIndexPath: calculate the height required for your label (it is important you have your label correctly configured for multiline and/or word wrapping)
Calculate the required height of label
CGRect frame = [label.text boundingRectWithSize:CGSizeMake(cell.width, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin attributes:#{NSFontAttributeName: font} context:nil];
Return the calculated height plus padding
frame.size.height + TopPadding + Bottom Padding
This is a general approach to have a dynamically sizing cell.
Note: Sometimes this is off by a few points so you may need to add up 5 extra points in the cell height to get all the text fitting in the label.
Please write following line in viewDidLoad:
_tableView.rowHeight = UITableViewAutomaticDimension;
Please make sure of following points:
Dont create height constraint of label
Make width of that label equal to screen size or content view
Apply leading, trailing, top and bottom constraint
Dont write heightForRowAtIndexPath method
Please let me know the results
EDIT :
Write following line in your cellForRowAtIndexPath method
myLabel.preferredMaxLayoutWidth = cell.contentView.frame.size.width;

Having 2 multiline labels on single UITableViewCell in iOS 8

I have a scenario in which a single UITableViewCell have 2 UILable. I can have long text in it coming from server which causes both labels to be multiline at same time.
I have implemented autolayout and
label.numberofline = 0;
tableVieww.estimatedRowHeight = 100.0;
tableVieww.rowHeight = UITableViewAutomaticDimension;
but it results only one label to expand not both. Please help.
Thanks in advance
try this:
use this code to calculate row height
Note : ExtraHeight"H"
Suppose you have cell with height 100 and in that cell a label has height 20 than extra height will be 80, because this code is calculating the height of label as per text with its size.
you are going to put this code in heightforRowatindexpath so cell.label can't get there so just pass the text and use Method-2
Method - 1:
-(CGFloat)setRowHeightWithLabel:(UILabel *)lbl withLabelText:(NSString *)lblText withExtraHeight:(CGFloat)H withFont:(CGFloat)fontSize
{
CGFloat totalHeight;
CGFloat lblWidth = lbl.frame.size.width;
CGSize lblTextSize = [lblText boundingRectWithSize:CGSizeMake(lblWidth, MAXFLOAT)
options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
attributes:#{NSFontAttributeName: [UIFont systemFontOfSize:fontSize]} context:nil].size;
if (lblTextSize.height > lbl.frame.size.height) {
totalHeight = (lblTextSize.height+H);
}
else
{
totalHeight = lbl.frame.size.height+H;
}
NSLog(#"+++++++++++++Height - %.2f",totalHeight);
return totalHeight;
}
Use this for use in heightforRow method
Method - 2:
-(CGFloat)setRowHeightWithLabelText:(NSString *)lblText withExtraHeight:(CGFloat)H withFont:(CGFloat)fontSize
{
CGFloat totalHeight;
CGFloat lblWidth = 300;
CGSize lblTextSize = [lblText boundingRectWithSize:CGSizeMake(lblWidth, MAXFLOAT)
options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
attributes:#{NSFontAttributeName: [UIFont systemFontOfSize:fontSize]} context:nil].size;
if (lblTextSize.height > 20) {
totalHeight = (lblTextSize.height+H);
}
else
{
totalHeight = 20+H;
}
NSLog(#"+++++++++++++Height - %.2f",totalHeight);
return totalHeight;
}
I think you are using autolayout I had the same problem I resolved it by setting maximum width of labels and the in label's size Inspector you should set preferred width to your max width
What You have so far looks fine. That should work without the need calculate the label height as some suggested.
Just make sure that you have the proper constraints on your labels.
Top constraint between the top label and its superview.
Bottom constraint between the bottom label and its superview.
A vertical spacing constraint between the two labels.
I tested it. it's working!
- (void)viewDidLoad {
[super viewDidLoad];
dynamicTableVuew.rowHeight = UITableViewAutomaticDimension;
dynamicTableVuew.estimatedRowHeight = 100;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"CellId"];
UILabel *label1 = (UILabel *)[cell viewWithTag:1];
UILabel *label2 = (UILabel *)[cell viewWithTag:2];
label1.text = #"Very long text Very long text Very long text Very long text Very long text Very long text Very long text Very long text Very long text Very long text Very long text Very long text Very long text Very long text Very long text Very long text Very long text Very long text";
label2.text = #"Very long text Very long text Very long text Very long text Very long text Very long text Very long text Very long text Very long text Very long text Very long text Very long text Very long text Very long text Very long text Very long text Very long text Very long text";
return cell;
}
That's all I have in the view controller. and nothing special in storyboard.
One last thing to check. Make sure that your tableview is connected to your view controller with an outlet. You may see the outlet code there but does not mean its connected. maybe it was removed by mistake. the following lines will not take effect:
tableVieww.estimatedRowHeight = 100.0;
tableVieww.rowHeight = UITableViewAutomaticDimension;
If you want two labels to be multi-line (supposing you are using "Subtitle" cell type"), you must set numberOfLines to 0 to both labels, eg:
UITableViewCell cell = [UITableViewCell alloc]init];
cell.textLabel.numberOfLines = 0;
cell.detailTextLabel.numberOfLines = 0;
Your lines about cell height seems to be correct

Table cell label not wrapping last line in iOS7

I am getting very strange problem in my app. I am creating table view cell dynamically. And adjusting height of cell label according to content.
My problem is that my cell label is not showing last line after wrapping means if there are total three lines for my label then label shows only two lines. The code was working on iOS6 but on iOS 7 it is giving problem.
[labelCell.contentView bringSubviewToFront:labelCell.textLabel];
labelCell.textLabel.numberOfLines = 0;
labelCell.textLabel.lineBreakMode = NSLineBreakByWordWrapping;
NSString *fieldLabel = labelCell.textLabel.text;
CGSize textSize = [self sizeForLabelWithString:fieldLabel width:600.0f andIndexPath:indexPath];
float newHeight = textSize.height+22.0f;
labelCell.height = newHeight;
use this method:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *fieldLabel = labelCell.textLabel.text;
CGSize textSize = [fieldLabel sizeWithFont:[UIFont fontWithName:#"Georgia" size:17.0f] constrainedToSize:CGSizeMake(600, MAXFLOAT) lineBreakMode:NSLineBreakByWordWrapping];
float newHeight = textSize.height+22.0f;
return newHeight;
}
Add below code to cellForRowAtIndexPath
UILabel *lblfield=[[UILabel alloc] init];
NSString *fieldLabel=[NSString stringWithFormat:#"%#",labelCell.textLabel.text];
CGSize textSize = [fieldLabel sizeWithFont:[UIFont fontWithName:#"Georgia" size:17.0f] constrainedToSize:CGSizeMake(600, MAXFLOAT) lineBreakMode:NSLineBreakByWordWrapping];
float newHeight = textSize.height+22.0f;
lblfield.frame=CGRectMake(10, 0, 600, newHeight);
lblfield.backgroundColor=[UIColor clearColor];
lblfield.text=strusername;
[cell addSubview:lblfield];
I was having the same issue and just stumbled across this. My label was resizing to the correct size, but it wasn't showing the last line on any labels that wrapped to several lines. Moreover, when I selected/unselected the cell, I could suddenly see the last line.
I was able to resolve the issue by adding a small fudge factor (2 points) to the height of my cell. I updated the value to use for the height of the cell from:
return labelHeight + 2 * kTopAndBottomPadding;
to:
return labelHeight + 2 * kTopAndBottomPadding + 2.f;
You are changing the label height based on the content. So you need to handle the cell height dynamically or need to set the height of a cell based on the content(Max among the string.).
i.e
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
return MAXStringHeght;
}
and try once.

UITableCell Height not adjusting properly

I have a UITableView that lists out the details of a certain item. Some of the details require more than one line to display properly.
I am using this code to dynamically resize the cell:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section == 1) return 320;
CGSize maxSize = CGSizeMake(280, MAXFLOAT);
CGSize cellSize = [[[appDelegate.callList objectAtIndex:callID] objectAtIndex:indexPath.row+1]
sizeWithFont:[UIFont systemFontOfSize:17]
constrainedToSize:maxSize
lineBreakMode:NSLineBreakByWordWrapping];
return cellSize.height+10;
}
It is a cell with Right Detail style. Nothing else. The detail textlabel is size 17 font.
Using this code, I get cells that cut off the cell below:
I know I could obviously just increase the +10 at the end, but then my cells would be too big for my liking.
Any help appreciated!
EDIT
I have found the issue. The width set in maxSize was too large.
Is there any way to find out the current detaillabel with without entering it manually prior?
Please refer below link, its an example of Dynamic Height UITableView Cells in Xcode: It may help you.
http://samrayner.com/posts/dynamic-tableview-cells/
You can use
CGSize maximumSize = CGSizeMake(300, 9999);
NSString *myString = #"This is a long string which wraps";
UIFont *myFont = [UIFont fontWithName:#"Helvetica" size:14];
CGSize myStringSize = [myString sizeWithFont:myFont
constrainedToSize:maximumSize
lineBreakMode:self.myLabel.lineBreakMode];
to calculate the displaying size of a givin NSString. So you can alter your cell's height according to the codes above. And also, you should reload your tableview after the heigth of some cell is changed.

NSString sizeWithFont:constrainedToSize: computing wrong height

I have a Subtitle style UITableViewCell which height changes dynamically depending on the length of the text for each field. The problem is that the textLabel's height (CGSize size) does not increase if the label has multiple lines.
The weird part is that the detailTextLabel's height is increasing as it should (CGSize size2). The code to calculate both heights are identical.
Here is my function:
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
SETLISTFMNS0Song *song = [[[selectedSetlist.sets objectAtIndex:indexPath.section] songs]objectAtIndex:indexPath.row];
CGSize size = [song.name sizeWithFont:[UIFont fontWithName:setlistFont size:labelFontSize] constrainedToSize:CGSizeMake(self.setsTable.bounds.size.width, CGFLOAT_MAX)];
NSLog(#"Label: \"%#\" \tLabel Size: %f W %f H", song.name, size.width, size.height);
NSMutableString *detail;
if ([song cover]) {
detail = [[NSMutableString alloc] initWithFormat:#"(%# cover)", [[song cover] name]];
}
if ([song with]) {
if (!detail) {
detail = [[NSMutableString alloc] initWithFormat:#"(with %#)", [[song with] name]];
}
else {
[detail appendFormat:#" (with %#)", [[song with] name]];
}
}
if ([song info]) {
if (!detail) {
detail = [[NSMutableString alloc] initWithFormat:#"(%#)", [song info]];
}
else {
[detail appendFormat:#" (%#)", [song info]];
}
}
if (detail.length != 0) {
CGSize size2 = [detail sizeWithFont:[UIFont fontWithName:setlistFont size:detailFontSize] constrainedToSize:CGSizeMake(self.setsTable.bounds.size.width, CGFLOAT_MAX)];
size.height += size2.height;
NSLog(#"Detail Label: \"%#\" \tDetail Label Size: %f W %f H", detail, size2.width, size2.height);
}
return size.height + 5;
}
I am also setting both textLabel's numberOfLines property to 0 in cellForRowAtIndexPath to support multiple lines:
cell.textLabel.numberOfLines = 0;
cell.detailTextLabel.numberOfLines = 0;
UPDATE: Thanks to #josh I now understand why this is happening. I had the width constraints set to the width of the UITableView, which is too wide. Anyone know how to find the width of the UILabel before it is created? HA!
Thanks!
How long are the strings you're calculating the size against? I ask because you're sizeWithFont:constrainedToSize: function is constraining to the full width of the cell, but your labels are probably not the full width of the cell.
What I suspect is happening is song.info is just short enough that it would fit on one line if the line were the full width of the cell, and that your song detail is long enough that it is calculating the correct number of lines, but not so long as to exceed the calculated height.
All of that to say, I think what you need to do is find out the widths of textLabel and detailTextLabel and set your constraints to those values.
Update - A way of calculating label widths
Since the width of the labels inside of a cell are dependent on the width of the cell, and since cell's aren't created at the time heightForRowAtIndexPath: is called, we need to come up with a way to know the labels' widths before they the widths are set. The only way to do this is to set the widths ourselves. Here's how I would do it:
MyCell.h
#import <UIKit/UIKit.h>
#interface MyCell : UITableViewCell
+ (CGFloat)textLabelWidthForCellOfWidth:(CGFloat)cellWidth;
#end
MyCell.m
#import "MyCell.h"
#implementation MyCell
- (void)layoutSubviews {
[super layoutSubviews];
CGRect frame = self.textLabel.frame;
frame.size.width = [MyCell textLabelWidthForCellOfWidth:self.frame.size.width];
self.textLabel.frame = frame;
}
+ (CGFloat)textLabelWidthForCellOfWidth:(CGFloat)cellWidth {
// This calculation can be as complex as necessary to account for all elements that affect the label
return cellWidth - 20;
}
#end
Then in your heightForRowAtIndexPath: implementation you can call the same class method:
CGFloat labelWidth = [MyCell textLabelWidthForCellOfWidth:self.tableView.frame.size.width]; // Since non-grouped cells are the full width of the tableView
CGSize size2 = [detail sizeWithFont:[UIFont fontWithName:setlistFont size:detailFontSize] constrainedToSize:CGSizeMake(labelWidth, CGFLOAT_MAX)];
You would create a separate Class Method (+) for each label that you need to reference.
as looking at your code i found you are missing to define "lineBreakMode".
CGSize theSize = [song.name sizeWithFont:[UIFont fontWithName:setlistFont size:labelFontSize] constrainedToSize:CGSizeMake(self.setsTable.bounds.size.width, CGFLOAT_MAX) lineBreakMode:UILineBreakModeWordWrap];
update your code with this. i hope it will fix your problem. Good luck

Resources