iOS Tableview with Dynamic height - ios

I am working on Tableview with dynamic cell height.
Due to my requirement, i have to show 40 types of different cell.Each cell is different.
For ex.
one cell having 2 labels,1 imageview
another cell having only 2 imageview
another cell having 5 labels,1 textview,2 buttons, 2 imageview
My problem is i cant able to define the height statically.ie. labels and textview in each cell is based on the text at run time.So according to the individual elements i need to adjust the height.So i have calculated the label and textview height based on below coding,
CGSize constrainedSize = CGSizeMake((IS_IPAD)?765:285 , 9999);
NSDictionary *dict=[array objectAtIndex:indexPath.row];
NSDictionary *attributesDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
[UIFont fontWithName:#"Lucida Sans" size:(IS_IPAD)?18.0:12.0], NSFontAttributeName,
nil];
NSMutableAttributedString *string = [[NSMutableAttributedString alloc] initWithString:[dict valueForKey:#"response"]attributes:attributesDictionary];
CGRect requiredHeight = [string boundingRectWithSize:constrainedSize options:NSStringDrawingUsesLineFragmentOrigin context:nil];
return requiredHeight.size.height;
The above code works fine.But it's little bit difficult to calculate for 5-10 labels for a cell.Because i need to call 10 times for every cell.So it causes slow scrolling on tableview.Also after that i need to change every label/textview and imageview's y position frame.Is there any alternate to achieve this? Any help would be highly appreciated.
Thanks.

Initially set a placeholder height for all your cells. later try to reload cells with exact heights.
Write a method that is capable of calculating the approx height for a specific cell. And pass some parameters into it.

Related

UITableViewCell fit textLabel to entire frame

I'm trying to get my UITableViewCell.textLabel property to autofit text both vertically and horizontally.
Right now my tableView is not scrollable, so the cell frame is not dynamic. I need the textLabel property to word wrap and resize to a set # of lines. Setting the numberOfLines to 0 isn't working because it cut off because my cell height is smaller than the textLabel final height. Using an arbitrary number for numberOfLines cuts off the text.
How can I resize my textLabel to fit within the frame of the cell?
Code below
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell* cell = (UITableViewCell*)[tableView #"mycell"];
cell.textLabel.text = #"LOTS OF TEXT";
cell.textLabel.textAlignment = NSTextAlignmentCenter;
[cell.textLabel textRectForBounds:cell.bounds limitedToNumberOfLines:0];
cell.textLabel.lineBreakMode = NSLineBreakByWordWrapping;
cell.textLabel.numberOfLines = 0;
cell.textLabel.adjustsFontSizeToFitWidth = YES;
cell.textLabel.minimumScaleFactor = .5;
}
EDIT: If the cells are a set height this is straightforward. You will have to set a custom cell and textLabel in it, as I don't think you can't modify the textLabel in the basic or other preset cells the way you need to. Just add a text label and set constraints linking it to the four sides, with the minimum amount (can be zero). Labels automatically center text vertically if there is extra space, so making the label too tall shouldn't be a problem.
Original answer:
If you're not using tableView self-sizing cells, maybe to support iOS 7, then it won't matter what you do in the cell because the issue is in the tableView row heights. If a single label the classic boundingRect method will work. in tableView:heightForRowAtIndexpath: do
NSString *stringFromDataSource = #"Text For Label";
CGSize potentialSize = CGSizeMake(CGRectGetWidth(self.tableview.frame), CGFLOAT_MAX);
NSStringDrawingOptions optionsForMultiline = NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading;
NSDictionary *attributes = #{
NSFontAttributeName : [UIFont preferredFontForTextStyle:UIFontTextStyleBody]
}; //or whatever
CGRect rectForText = [stringFromDataSource boundingRectWithSize:potentialSize
options:optionsForMultiline
attributes:attributes
context:nil];
return CGRectGetHeight(rectForText);
Note that in your question, your various options for sizing the cell aren't going to be used if the textLabel is expanding with autolayout, unless there is a constraint capping the maximum size, at which point minimumScaleFactor and so on will kick in.

ios7 AutoLayout tableViewCell

I currently have a custom UITableViewCell with a number of labels in it. Not all of those labels will necessarily have a value but they could do - and they may be multiline (At least 2 labels will always be visible). If there isn't any text then the label should collapse. What I'm trying to achieve is that each label only takes up the height it needs and they all butt up to each other. I've got all of this working, except I finally want a bottom margin of 11 between the last label and the cells content view with the cell height adjusted accordingly. This is the only bit where I can't seem to get my constraints working correctly.
I correctly return the right height by creating a dummy cell, and in my cellForRowAtIndexPath method I try to set the cell and the cell's contentview frame accordingly. But the cell height that is rendered on the screen is always the same as it was defined in the xib.
I know there's a lack of code here, but all my constraints have been define in IB and each label has a trailing and leading space for with and a top space of 0 to the label above it. The top label has a top space to create a top margin to the content view, but as soon as I do this on the bottom label it stretches the height of the labels to accommodate all the constraints.
I've seen various tutorials and questions on here that relate to 2 labels where 1 might be a variable size, but I haven't been able to adapt any solutions for what I'm trying to achieve.
Okay,
Get as many labels you want (suppose you want 2 labels inside the cell,)
Create 2 labels with height 1 in storyboard, or if you are programmatically adding them, then you can do.
UILabel *myLabel1 = [[UILabel alloc]initWithFrame:[CGRectMake:(x,y,width,1)]; // assuming you know their x,y and width respectively as you need them.
Now add constraints to the labels (Be sure you make them ambiguous or else orientation would mess it up, ):
3 a. Height -(should be equalto OR greater than => 1).
b. Width - [Set it a width],Make sure it has a priority more than others but less than height
c. Pin to trailing and leading space, as well as superview top and bottom.
d. If there are two Labels make sure you click both of them and add a Vertical or horizontal space according to your needs.
I think that would make it ambiguous. (I am telling these as you wrote its about autolayout, so despite of orientation this would never get any layout problems).
Add a snippet that would calculate the height of the Label when you know the string.
CGSize constrainedSizeOfMessege = CGSizeMake(widthOfLabel, 9999);//150,180 anything you like
NSDictionary *attributesDictionaryMessege = [NSDictionary dictionaryWithObjectsAndKeys:
[UIFont fontWithName:#"System Italics" size:16.0], NSFontAttributeName,
nil];
NSMutableString *myString = [[NSMutableString alloc]initWithString:[[friendsInstanceArray objectAtIndex:indexPath.row] myString] attributes: attributesDictionaryMessege];
CGRect requiredHeightMessege = [myString boundingRectWithSize:constrainedSizeOfMessege options:NSStringDrawingUsesLineFragmentOrigin context:nil];
Add the above code in
(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
Now, calculate the height of the Cell, the height of all the labels if they are 1 height then
Return the height of the Cell in storyboard + height of the Expected Label Size.
So The method would look like.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
CGSize constrainedSizeOfMessege = CGSizeMake(widthOfLabel, 9999);//150,180 anything you like
NSDictionary *attributesDictionaryMessege = [NSDictionary dictionaryWithObjectsAndKeys:
[UIFont fontWithName:#"System Italics" size:16.0], NSFontAttributeName,
nil];
NSMutableString *myString = [[NSMutableString alloc]initWithString:[[friendsInstanceArray objectAtIndex:indexPath.row] myString] attributes: attributesDictionaryMessege];
CGRect requiredHeightMessege = [myString boundingRectWithSize:constrainedSizeOfMessege options:NSStringDrawingUsesLineFragmentOrigin context:nil];
int heightOfMessege = requiredHeightMessege.size.height;
//if cell height is 50 then return 50+heightOfMessege
return 50+heightOfMessege;
}
And YES POSITIVELY set, mylabel.numberOfLines = 0;
Hope this helps you out
If you want to stick labels on their position including with the empty space than give a single space in label's title text which will not make their text empty and than label will stick to positions.

Change label height in tableview in iOS 7

I have a label in custom cell in table view.
I want to change cell height and also label height(at first I am showing only 2 line, I want to show more text) after user taped a cell,
I am able to change cell height based on cell content, but unfortunately I cannot change label height, :((
I've read tons of stackoverflow answers, but still nothing.
it is believed that this would work:
CGSize labelSize = [#"Hello World!" sizeWithFont:[UIFont systemFontOfSize:17] constrainedToSize:CGSizeMake(label.frame.size.width,MAXFLOAT) lineBreakMode:NSLineBreakByWordWrapping];
but this is deprecated in iOS 7; can any one please help me in resizing my label in cell?
If you want the height of your label relative to the height of your cell and you use Storyboard, you should determine the size of your label with constraints in relation to the ContentView of the cell. Just set the top and bottom distance from your label to the ContentView and no additional height for the label.
If you dont know how to set Storyboard and constraints, this might help: https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/AutolayoutPG/AutoLayoutbyExample/AutoLayoutbyExample.html
UITableViewCell lays out it's content in -layoutSubviews. Therefore, if you want to simply have a custom layout logic, you need to subclass UITableViewCell and override the -layoutSubviews method. It's a good idea to call super anyway before applying your logic, though.
You may use something like this to get UIlabel size
-(CGFloat)getLabelSize:(UILabel *)label fontSize:(NSInteger)fontSize
{
NSDictionary *attributesDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
[UIFont systemFontOfSize:fontSize], NSFontAttributeName,
nil];
CGRect frame = [label.text boundingRectWithSize:CGSizeMake(270, 2000.0)
options:NSStringDrawingUsesLineFragmentOrigin
attributes:attributesDictionary
context:nil];
CGSize size = frame.size;
return size.height;
}

UITableViewCell dynamic height

I've done a lot of reading already on this, but it's seems like there's no simple solution.
I'm trying to make an app that loads an NSArray of NSString comments to display in a UITableView. The comments all vary in size.
How can I get the cell to adjust its size to show the entire content of each comments?
I'm trying to find a simple solution without resorting to using magic CFloat numbers.
Is there a method in apple's API that allows me to calculate the needed height of the cell.detailTextLabel given an NSString comment and fixed width?
I think if I can calculate this height, all that's need is to set the height of the cell and the height of the row.
Not really sure what order to do this in since I've read the cell hasn't been created yet when heightForRow:AtIndexPath: gets called.
Calculate the height of the text in tableView:heightForRowAtIndexPath:
You need to use boundingRectWithSize:options:context: on iOS 7+ and sizeWithFont:forWidth:lineBreakMode: on iOS 6 and below. See the apple documentation for more information.
UIFont *font = [UIFont oka_commentLabelFont];
NSString *text = [self commentForIndexPath:indexPath];
CGFloat cellWidth = 300.f;
CGSize boundingSize = CGSizeMake(widthForCell, CGFLOAT_MAX);
CGSize size;
if ([text respondsToSelector:#selector(boundingRectWithSize:options:attributes:context:)]) {
size = [text boundingRectWithSize:boundingSize
options:NSStringDrawingUsesLineFragmentOrigin
attributes:#{ NSFontAttributeName : font }
context:nil].size;
} else {
size = [text sizeWithFont:font
constrainedToSize:boundingSize
lineBreakMode:NSLineBreakModeWordWrap];
}
return size.height;
You need to set the font to the same font you want to use on the cell. If you put this in a performUpdates block on the tableView then you will get a nice expanding animation.
Don't set the height of the cell, set the height of the row and the table view will do the rest.
To calculate the height of the text, ask a label with textRectForBounds:limitedToNumberOfLines:, or ask the string with one of the many methods like sizeWithFont:constrainedToSize:lineBreakMode:.
You may need to deal with padding around the label when compared to the size of the cell.
yes we can calculate the height of UILabel depending on the Font and line break mode.
UIFont * font = [UIFont systemFontOfSize:12.0];
CGSize newSize = [text sizeWithAttributes:#{NSFontAttributeName:font}];// You can add other attributes in dictionary to like line break mode.
Here you got new size for the text which will be in UILabel, now in hegihtForCellAtIndexPath method you can change the size of UITableViewCell. newSize.height is height you need for label, now you can add some value to it for offsets and return it.
Use
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
return [super tableView:tableView heightForRowAtIndexPath:indexPath];
}

How to find out when UILabel wordwraps

I have created a couple of different UITableViewCells for my tableViewController, this is because I have different bits of data I want to display depending what comes back. Because of this each UITableViewCell is of a different height.
This is all fine, However one of my UILabels has to display a large NSString, so large that I have had to word wrap it onto a second line, The only issue here is that it messes up my UITableViewCell formatting.
My question is, is it possible to flag or capture some type of action when a UILabel receiving a NSString has to use wordrap because the size of the NSString is too long?
Or is there a way to calculate the physical length (not how many chars are in the string) of the NSString so I can decide hey I need to reformat my UITableViewCell..
Any help would be greatly appreciated.
The usual way is to use sizeWithFont:constrainedToSize:lineBreakMode: to get the size of a string. You use it like this:
CGSize stringSize = [theString sizeWithFont:[UIFont fontWithName:#"Helvetica Neue" size:12] constrainedToSize:CGSizeMake(320, 3000) lineBreakMode:NSLineBreakByWordWrapping ];
This is set for the full width of a table cell, but you would want to use the width of your label instead.
i dont know if i understand well but you have the height of your tableviewcell right? and you have a NSString maybe in a UITextView and this height of content of textview is higher then tableviewcell. Well, you should first calculate the content of UITextview, add into a list and when heightforRowAtindexPath was called, you should calculate new height (content textview) plus something... And to solve the max length you should count a limit for chars or limit for lines..
Some usefull code:
//resize height with content of UITextView
CGRect frame = _textView.frame;
frame.size.height = _textView.contentSize.height;
_textView.frame = frame;
//delegate textview to calculate limit for text.
- (void)textViewDidChange:(UITextView *)textView{
NSInteger restrictedLength=140;
NSString *temp=textView.text;
if([[textView text] length] > restrictedLength){
textView.text=[temp substringToIndex:[temp length]-1];
}
}
remember, you need to calculate the limit/size content from UITextview before heightforRowAtIndexPath called. When it called you already need to know your max height for cell.

Resources