UITableViewCell Auto Resizing Multiple UILabels - objective-c

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];

Related

Changing height of UITableViewCell Dynamically

I am trying to show comments of each User in my TableView. The comments can BE accommodated by an Image.
Usually We can set height of a UITableViewCell as heightForRowAtIndex. However I want each Cell to Expand according to the Chat And if Image included upto image height.
How can I increase the height of UITablViewCell as per its contents?
You're still going to have to do it in heightForRowAtIndex:, except that you'll have to dynamically determine the height.
I'm envisioning something like this:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
CommentModel *comment = self.comments[indexPath.row];
CGFloat height = [CommentTableViewCell heightForComment:comment];
return height;
}
And then in your CommentTableViewCell, you have a class method that goes something like:
// Calculates the height a CommentTableViewCell should be when configured with the given comment
+ (CGFloat)heightForComment:(CommentModel *)comment {
// This part of the code will be very specific to your own project
CGFloat height = BASE_HEIGHT;
height += comment.image.size.height;
height += comment.message.size.height;
return height;
}
I know that this code probably doesn't match your code base, but it should give you a general idea of one way your goal can be accomplished.
USE THIS CODE IF YOU DONT HAVE CUSTOM CELL CLASS.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
float PADDING = 0.5f; // USE FOR DIFFERNCE BETWEEN YOUR ENDING TEXT AND SEPERATOR
UIImage *image =[UIImage imageNamed:#"test.png"]; // Some Image you want to put dynamically.
NSString *text = #"Sometext That you want tro fill Dynamically";
CGSize textSize = [text sizeWithFont:[UIFont boldSystemFontOfSize:14.0f] constrainedToSize:CGSizeMake(270 , 1000)];
return ((textSize.height+image.size.height+ PADDING * 3) + 30);
}
IF YOU HAVE CUSTOM CLASS THEN YOU HAVE TO PASS THE HIEGHT TO CUSTOM CELL TO MANAGE YOU LABEL HIEGHT SAME AS YOU EXPAND YOUR CELL OVERTHERE. YOU CAN DO IT SEPARATELY IN CELL CLASS BUT TO SYNCHRONIZE IT WITH YOUR ACTUAL HIEGHT F CELL. YOU HAVE TO PASS HIEGHT IN CUSTOM CLASS WHEN YOU WILL SETTING ITS VALUES.

Dynamic table cell height with Autolayout iOS 6 +

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.

iOS: Re-used UITableViewCell's imageView property does not respect contentMode or clipsToBounds [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Changing bounds of imageView of UITableViewCell
I have a custom UITableViewController, and within I am dynamically styling a UITableViewCell with style UITableViewCellStyleSubtitle. All is good, except that when a cell is re-used, its imageView property does not respect my contentMode or clipsToBounds settings. Ideally, I would prefer the content to adhere to the default size/shape (which I believe is 40x40 square).
There are other posts (links below) that suggest subclassing UITableViewCell, or re-sizing your images to fit exactly, but both these feel like workarounds and (imho) would overly-complicate my code given that I am already pulling small (non-square) images.
Suggests subclassing UITableViewCell: Changing bounds of imageView of UITableViewCell
Suggests resizing all images: UITableViewCell's imageView fit to 40x40
Example code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *kCellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kCellIdentifier];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:kCellIdentifier];
}
NSString *mainText = #"mainText";
NSString *subtitle = #"subText";
[[cell textLabel] setText:mainText];
[[cell detailTextLabel] setText:subtitle];
// get album cover
UIImage *imageForCell = [album objectForKey:#"coverImage"];
// this is the broken part -
// it works upon first load, but it is NOT applied when a cell is re-used/dequeued..
// instead, the image is displayed un-scaled and un-square
[[cell imageView] setAutoresizingMask:UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth];
[[cell imageView] setContentMode:UIViewContentModeScaleAspectFill];
[[cell imageView] setClipsToBounds:YES];
if (imageForCell) {
[[cell imageView] setImage:imageForCell];
} else {
/* code to retrieve custom image */
}
return cell;
}
What gives? Is there a bug in UITableViewCell? Or is this for some reason by design?
I'm pretty sure Apple claims ownership of textLabel, detailTextLabel, and imageView with respect to layout, so I don't think you can call this a defect.
-tableView:willDisplayCell:forRowAtIndexPath: is an API specifically for formatting the layout of a cell. You should have better luck making formatting changes there.
Didn't work despite what the doc implied.

How to get the REAL height of UITextView (content + paddings + whatever is needed)

I cannot get the real height of a UITextView after trying the suggestion in the forums like:
How do I size a UITextView to its content?
Resizing UITextView
This solution make the UItextView resize to its content, but I need to know the real height of the UItextView so I can position the rest of views without overlapping.
I have a UITableView each cell displays an UITextView.
I get the size of the UITextView, resize it and resize the cell containing it with the following code:
//self.descriptionTV is a UITextView
self.descripcionTV.text = self.detailItem.descripcion;
//I calculate the height (altura) to size the UITextView and to later size the cell
NSNumber *altura = [NSNumber numberWithFloat:
(self.descripcionTV.contentInset.top + self.descripcionTV.contentSize.height + self.descripcionTV.contentInset.bottom)];
//Here I size the UITextView
CGRect frame = self.descripcionTV.frame;
frame.size.height = altura.floatValue;
self.descripcionTV.frame = frame;
//I use this in tableView:heightForRowAtIndexPath:
[self.cellsToLoad addObject:[NSArray arrayWithObjects:self.cellDescripcion, altura, nil]];
-(float)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
//La altura de la celda la tenemos almacenada en el array cells
float altura = [[[self.cellsToLoad objectAtIndex:indexPath.row] objectAtIndex:1] floatValue];
return altura;
}
Unfortunatelly this does not get the job done. The Cell after this gets overlapped by some pixels. I have been using UILabel instead of UITextViews before with no problem.
I know a solution is just to increment manually the height calculated, but I would like to know if there is a real method for getting the size of a UITextView.

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;