Dynamic table cell height with Autolayout iOS 6 + - dynamic

I have UITableviewCell subclass. In that cell, I have 2 labels (lblComment and lblDateTimeStampe) and one view to show rating stars.
I want dynamic height of lblComment to fit all the text. It should expand & shrink in height depending on the length of comment.
I have implemented this before but WITHOUT AutoLayout like below
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *label = self.userComment.commentText;
CGSize stringSize = [label sizeWithFont:[UIFont boldSystemFontOfSize:15]
constrainedToSize:CGSizeMake(320, 9999)
lineBreakMode:UILineBreakModeWordWrap];
return stringSize.height+10;
}
Now I am using AutoLayout feature.
How can I achieve this using Autolayout?
Any kind of help is appreciated. Thanks

Unfortunately Auto Layout won't help you with tableView:heightForRowAtIndexPath. You still have to implement that method.
You can use UIView's systemLayoutSizeFittingSize: method but that means you'd have to instantiate and configure a table view cell which can be quite costly. You could keep one off-screen though and reuse it for calculations. But at this point, you don't really save much in terms of development effort, so doing the calculations as you did before manually is probably the best/fastest way to do this.

You can use the freely available Sensible TableView framework. The framework automatically resizes the cells as their content grows. It also does that dynamically if the table view is already displayed.

I have implemented a solution to the same problem with using autolayout and it works.
First, you need to define heightConstraint for lblComment.
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
UIFont *font = [UIFont fontWithName:#"YourFontName" size:YourFontSize] ;
UITextView *calculationView = [[UITextView alloc] init];
[calculationView setFont:font];
[calculationView setTextAlignment:NSTextAlignmentLeft];
[calculationView setText:lblComment.text];
int width = 0;
if(self.appDelegate.isDeviceiPhone)
width = 284;
else
width = 720;
CGSize size = [calculationView sizeThatFits:CGSizeMake(width, FLT_MAX)];
return size.height;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//initialize the cell..
UIFont *font = [UIFont fontWithName:#"YourFontName" size:YourFontSize];
UITextView *calculationView = [[UITextView alloc] init];
[calculationView setFont:font];
[calculationView setTextAlignment:NSTextAlignmentLeft];
[calculationView setText:cell.lblComment.text];
int width = 0;
if(self.appDelegate.isDeviceiPhone)
width = 284;
else
width = 720;
CGSize size = [calculationView sizeThatFits:CGSizeMake(width, FLT_MAX)];
cell.lblDetailHeightConstraint.constant = size.height;
// the other stuff...
}
Hope this helps.

If you setup the constraints correctly in IB this should work. You should not have to add the elements programmatically although as you said that will work as well.
Assuming that you have label1(variable height), label2, and view1 in the tableviewcell in that order you should:
Set fixed height constraints on label2 and view1
Pin the bottom of view1 to the bottom of the cell
Pin the vertical spacing of view1 and label2
Pin the vertical spacing of label2 and label1
Pin the top spacing of label1 to the top of the cell
Just make sure that you do NOT have a height constraint on label1, if you do it should only be greater than or equal to. With a configuration like this, you can continue using heightForRowAtIndexPath and label1 will expand and contract vertically based on the height of the cell.

Related

How to make UITextView in section header adjust its height to its content

I cannot get this to work. I am using autolayout on the current view controller. I have a UITableView that has section headers and each section header has UITextView that has text that varies in length depending on the section. I cannot make it enlarge its height automatically to fit the contents so there will be no need for scroll (its contents are attributed text)
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
//UITextView *tv = [[UITextView alloc] init];
//tv.editable = NO;
//tv.attributedText = [self millionaireResults][section][#"header"];
//return tv;
return [self millionaireResults][section][#"headerview"]; //this is a uitextview
}
// this did not workeither
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
UITextView *tv = [self millionaireResults][section][#"headerview"];
return tv.frame.size.height;
}
How can this problem be solved?
I updated the code per the suggestion of Michael below
Make your "UITextView *tv" object a property and then you can do something like this (assuming you only have exactly one section to your table view):
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
return (self.tv.frame.size.height);
}
If you have more sections (which is appears you do), you should make that property a NSArray of UITextView objects.
This also means you need to set the contents of your "tv" object before "viewForHeaderInSection:" gets called.
This is the answer that worked for me
When you are creating the UITextView, you must set the scrollEnabled
to false.
Your UITextView must be given the width that covers horizontal space otherwise auto size calculation are off (sometimes it is sometimes it is not, i think depending on wordbreak or something, but it was inconsistent!) and only fixes itself if you rotate the device to force redraw
In the heightForHeaderInSection method, you must get the
sizeThatFits and return its height as the height of your text view
Here is the height calculation (I found this on this site http://www.raywenderlich.com/50151/text-kit-tutorial )
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
UITextView *tv1 = (UITextView *)[self millionaireResults][section][#"headerview"];
// sizethatfits calculates the perfect size for this UITextView
// if you gave your UITextView full width
CGSize goodsize = [tv1 sizeThatFits:tv1.frame.size];
return goodsize.height+4; // here 4 is not necessary, i just put it as an offset
}
Here is the code that creates those UITextView objects
for (int i = 0; i < [milarr count]; i++) {
UITextView *tv = [[UITextView alloc] init];
tv.editable = NO;
tv.attributedText = milarr[i];
// labelTopTitle and this table in question have same width in an autoLayouted view
// so i am giving width of labelTopTitle to let UITextView cover full available
// horizontal space
tv.frame = CGRectMake(0, 0, self.labelTopTitle.frame.size.width,FLT_MAX);
//tv.backgroundColor = [UIColor grayColor];
//tv.textContainerInset = UIEdgeInsetsZero;
tv.scrollEnabled = NO;
[results addObject:#{#"headerview": tv,
#"rows":#[...]
}
];
}

UITableViewCell Auto Resizing Multiple UILabels

We are currently resizing the height of a UILabel in a UITableViewCell. Now the client wants to have both labels contained within the UITableViewCell to be resized based on the content. Researching this we see solutions everywhere for resizing a single label but nothing about multiple labels. Can somebody point us to a good resource for this issue?
your research for resizing label is correct , you need write the logic for resizing on one label only. if you see in
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
its return type uitableviewcell. it always return the same configuration for the cell(unless you are creating static cell for each row).
[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
this method dequeue the cell & reuse it . so you need to right the logic for resizing the label where you are creating your cell. or its better to right the resize logic in custom cell class. i am adding the code , which help me in this problem.
CGSize maximumLabelSize = CGSizeMake(270, FLT_MAX);
CGSize expectedLabelSize = [myString sizeWithFont:[UIFont fontWithName:#"Helvetica" size:16.0f] constrainedToSize:maximumLabelSize lineBreakMode:NSLineBreakByWordWrapping];
NSLog(#"Expected Size of label based on string--%#",NSStringFromCGSize(expectedLabelSize) );
//adjust the label the the new height.
CGRect newFrame = myLabel.frame;//get initial frame of your label
newFrame.size.height = expectedLabelSize.height;
myLabel.frame = newFrame;
NSLog(#"new frame of label--%#",NSStringFromCGRect(newFrame));
[myLabel setText:attString];

How to make UITableView row as wide as the label in it dynamically?

I have a UITableView where each row may have a label anywhere from no lines to any number of lines (realistically 3-4). I am wanting the row to be expanded based on the UILabelView contents.
I have this so far:
- (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
CGFloat height = 60.0;
UIFont *font = [UIFont fontWithName:#"Helvetica-BoldOblique" size:10.0];
NSString *text = reminder.notes; //the text that will be in the UiLabelView
CGFloat notesHeight = [text sizeWithFont:font
constrainedToSize:CGSizeMake(250.0, 4000.0)
lineBreakMode:UILineBreakModeTailTruncation].height;
height += notesHeight;
return height;
}
I still get screwy results. What can I do to accomplish my goal?
Thank you
you are using UILineBreakModeTailTruncation as lineBreakMode which will always result in a single line and sizeWithFont:constrainedToSize:lineBreakMode: will then return the needed size of that single line.
Try UILineBreakModeWordWrap instead.
edit: I hope you have set the numberOfLines-property of a UILabel to 0 (zero) so that your label is able to draw many lines.

How to modify the font size for the text in a grouped header of a table view?

I'm working witha simple tableview but I need to modify the font size for the text in the group header.
I've found this question on stackoverflow eferencing the tableview methods to override but I'm looking for an example of how I might modify the actual headers font size once I implement this method
Note: I'm able to modify the height of the header itself using interface builder but the font size appears to require some objective-c to modify this
Thank you in advance
Edit
here is what I have so far -it's not throwing an exception but the header itself doesn't show the text or font size I set on the label itself
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
UIView* x = tableView.tableHeaderView;
UILabel* y = [[UILabel alloc] initWithFrame:CGRectMake(5, 0, 310, 0)];
y.font = [UIFont boldSystemFontOfSize:12.0];
y.text = #"ha";
[x addSubview:y];
[y release];
return x;
}
The header for a table may be set to any subclass of UIView. In particular, you can create a UILabel, set the text with your desired font size, then make the label the headerView.
Three potential problems with your edit:
Did you remember to implement tableView:heightForHeaderInSection:?
The height of your UILabel is currently 0.
When this method is called, tableView.tableHeaderView may not yet be defined.
My approach would be to declare UILabel *headerLabel and then add this to viewDidLoad:
headerLabel = [[UILabel alloc] initWithFrame:CGRectMake(5, 0, 310, 15)];
headerLabel.font = [UIFont boldSystemFontOfSize:12.0];
headerLabel.text = #"Testing";
Then have
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
return 15.0;
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
return headerLabel;
}

Sizing a UILabel to fit?

How would one modify the following snippet (in a tableView:cellForRowAtIndexPath: UITableViewController method) from the "09a - PrefsTable" recipe from Chapter 6 of The iPhone Developer's Cookbook:
if (row == 1) {
// Create a big word-wrapped UILabel
cell = [tableView dequeueReusableCellWithIdentifier:#"libertyCell"];
if (!cell) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:#"libertyCell"] autorelease];
[cell addSubview:[[UILabel alloc] initWithFrame:CGRectMake(20.0f, 10.0f, 280.0f, 330.0f)]];
}
UILabel *sv = [[cell subviews] lastObject];
sv.text =  #"When in the Course of human events, it becomes necessary for one people to dissolve the political bands which have connected them with another, and to assume among the powers of the earth, the separate and equal station to which the Laws of Nature and of Nature's God entitle them, a decent respect to the opinions of mankind requires that they should declare the causes which impel them to the separation.";
sv.textAlignment = UITextAlignmentCenter;
sv.lineBreakMode = UILineBreakModeWordWrap;
sv.numberOfLines = 9999;
return cell;
}
...to size the "sv" UILabel subview and the "cell" UITableViewCell to be sized just big enough to fit the text (and work with more or less text, and other types of text alignment)?  I looked at the UILabel textRectForBounds:limitedToNumberOfLines: method, but the documentation states that it should not be called directly (and should only be overridden).  I experimented with the UIView sizeToFit method, without success.
Update: I asked a new question about my problem with the NSString -sizeWithFont:forWidth:lineBreakMode: method.
I had to do this enough that I extended UILabel to do it for me:
#interface UILabel (BPExtensions)
- (void)sizeToFitFixedWidth:(CGFloat)fixedWidth;
#end
#implementation UILabel (BPExtensions)
- (void)sizeToFitFixedWidth:(CGFloat)fixedWidth
{
self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, fixedWidth, 0);
self.lineBreakMode = NSLineBreakByWordWrapping;
self.numberOfLines = 0;
[self sizeToFit];
}
#end
then to have a label to have a variable multiline height but a fixed width just:
[myLabel sizeToFitFixedWidth:kSomeFixedWidth];
You should use NSString's -sizeWithFont:forWidth:lineBreakMode: method to retrieve the associated sizing metrics for your label.
Also, change the numberOfLines property to 0 if you're going to use that code.
NSString's -sizeWithFont:forWidth:lineBreakMode: does not actually perform the word wrap. Instead, use -sizeWithFont:constrainedToSize:lineBreakMode: to get an accurate width AND height value for the string.
Try this:
sv.text = #"When in the Course of human events, it becomes necessary for one people to dissolve the political bands which have connected them with another, and to assume among the powers of the earth, the separate and equal station to which the Laws of Nature and of Nature's God entitle them, a decent respect to the opinions of mankind requires that they should declare the causes which impel them to the separation.";
sv.textAlignment = UITextAlignmentCenter;
sv.lineBreakMode = UILineBreakModeWordWrap;
sv.numberOfLines = 0;
[sv sizeToFit];
Also, you will need to implement the UITableViewDelegate method:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
And have it return a total cell height adjusted for the resized text field.
One other note - Size to Fit should actually work, if you have number of lines set to 0 as previously mentioned. It would give you back a size with the height increased to accomidate the word-wrapped text set in the label and the width set to whatever the original label width had.
That will not help you though as you need to get the size in heightForRow before the cell is obtained, so you are better off calculating the height needed (and very probably caching that calculation so as not to slow down table rendering)
Here's a bit of code i use:
CGSize textSize = [myLabel.text sizeWithFont:myLabel.font];
I had similar problem, I had a UITableViewCell that was designed in StoryBoards as a static cell. I used [super tableView:cellForRowAtIndexPath:] to get it. So I wanted to resize the UILabel "detailTextLabel" so it fits the text I set to it. The style was "Right Detail".
I just set the text in my tableView:cellForRowAtIndexPath:. And than in tableView:heightForRowAtIndexPath: I returned
UITableViewCell *cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];
return cell.detailTextLabel.frame.size.height
I had long string. And finally had a wide Cell with 4 lines of text in label.
I had similar problem.
I solved this.
In cellForRowAtIndexPath method set font size to whatever you want.
cell.textLabel.lineBreakMode = UILineBreakModeWordWrap;
cell.textLabel.numberOfLines = 0;
[cell.textLabel setFont:[UIFont systemFontOfSize:14.0]];
[cell.textLabel sizeToFit];
And in heightForRowAtIndexPath method increase font size.
CGFloat height;
UITableViewCell *cell = [self tableView:tableView cellForRowAtIndexPath:indexPath];
NSString *text = cell.detailTextLabel.text;
CGSize constraint = CGSizeMake(320, 20000.0f);
CGSize size = [text sizeWithFont:[UIFont systemFontOfSize:20.0] constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap];
CGFloat calHeight = MAX(size.height, 44.0f);
height = calHeight + (CELL_CONTENT_MARGIN * 2);
return height;