Multi-line UILabel - ios

I've looked over older questions and tried all the suggestions, but still cannot seem to get a multi-line UILabel to work. I have a UITableView and the cell is created by tableView:cellForRowAtIndexPath:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *fieldValue = [self fieldValueAtIndexPath:indexPath];
NSString *fieldName = [self fieldNameAtIndexPath:indexPath];
NSString *title = [[self appDelegate] displayNameForFieldName:fieldName];
Field fieldCode = [[self appDelegate] fieldCodeForFieldName:fieldName];
DetailCell *cell = nil;
NSString *identifier = nil;
BOOL isNotes = [fieldName caseInsensitiveCompare:#"Notes"] == NSOrderedSame;
switch( isNotes ) {
case NO:
{
identifier = #"DetailCell";
cell = (DetailCell*)[tableView dequeueReusableCellWithIdentifier:identifier];
NSInteger rows = [self heightForText:fieldValue andFont:[self textFont] andWidth:cell.value.frame.size.width] / _oneRowSize.height;
cell.value.text = fieldValue;
cell.name.text = [title lowercaseString];
cell.name.numberOfLines = MAX( 1, rows );
cell.value.numberOfLines = cell.name.numberOfLines;
break;
}
case YES:
{
cell = (DetailCell *)[tableView dequeueReusableCellWithIdentifier:#"DetailCellNotes" forIndexPath:indexPath];
// cell = (DetailCell *)[tableView dequeueReusableCellWithIdentifier:#"DetailCellNotes"];
cell.value.text = #"This is a very long line of text which should take up several lines";
cell.name.text = [title lowercaseString];
cell.value.numberOfLines = 5; // No more than 5 lines of text
cell.value.backgroundColor = [UIColor purpleColor];
cell.value.lineBreakMode = NSLineBreakByWordWrapping;
cell.value.frame = CGRectMake(cell.value.frame.origin.x, cell.value.frame.origin.y, 180, 70);
[cell.value sizeThatFits:CGSizeMake(180., 70.)];
break;
}
}
cell.fieldName = fieldName;
return cell;
}
The height in the table view is defined like so
- (CGFloat) tableView:(UITableView*)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath
{
NSString *fieldName = [self fieldNameAtIndexPath:indexPath];
CGFloat height = 0.0;
if([fieldName isEqualToString:#"Notes"])
{
height = 70.;
}
else if([fieldName isEqualToString:#"Image"])
{
height = 100.;
};
return height;
}
which makes the cell large enough to hold a 3-line label. However when the cell appears the label is only one line (shown by the background being purple).
The tableview uses prototype cells, and I've also tried to set it to numberOfLines=5 and WordWrapping, but that didn't change the effects either. I've also tried both of the commented out lines (though searches suggest that sizeToFit might actually reset numberOfLines to 1).
I wonder what I've missed. I can't see any other place where the it might be overridden.
Thanks.

You are calling dequeueReusableCellWithIdentifier: to create your cell. This is a mistake, because it means that the cell has not assumed its final size. It is much better to call dequeueReusableCellWithIdentifier:forIndexPath:. This means that the cell will actually have the height that you are giving it in heightForRowAtIndexPath:. You should then be able to set the height of the label successfully.

Related

Xcode 6: Label in Table Cell won't expand / display longer text upon expansion / line up with cell

The Problem:
I've got a label in a table cell as follows:
EDIT: While the tableview does not use AutoLayout, the xib for the cell does. This is what it looks like:
Now, the "..." means the review (the text) is too long to be displayed. The user can then click on the cell, which would expand the cell and the label downwards, which would then show the rest of the text.
Here's the code for the heightForRowAtIndexPath:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
{
if (tableView == self.rateAndReviewView.ratingsTable) {
BOOL isSelected = [self.selectedIndexPaths containsObject:indexPath];
CGFloat maxHeight = MAXFLOAT;
CGFloat minHeight = 40.0f;
if (isSelected){
CGFloat constrainHeight = isSelected?maxHeight:minHeight;
CGFloat constrainWidth = tableView.frame.size.width - 20.0f;
//
SQLReview *review = [reviewsArray objectAtIndex:indexPath.row];
NSString *text = review.comment;
CGSize constrainSize = CGSizeMake(constrainWidth, constrainHeight);
CGSize labelSize = [text sizeWithFont:[UIFont systemFontOfSize:15.0f]
constrainedToSize:constrainSize
lineBreakMode:NSLineBreakByWordWrapping];
CGFloat labelHeight = labelSize.height;
return MAX(labelHeight+20, 100.0f);
} else {
minHeight = 100.0f;
return minHeight;
}
}
}
And this is the code for the cellForRowAtIndexPath:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if (tableView == self.rateAndReviewView.ratingsTable) {
static NSString *CellIdentifier = #"Cell";
VenueReviewCell *cell = (VenueReviewCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell==nil){
cell = [[[NSBundle mainBundle] loadNibNamed:#"ReviewCell" owner:nil options:nil] objectAtIndex:0];
}
[cell.contentView.layer setBorderWidth:0.5f];
cell.contentView.backgroundColor = [UIColor whiteColor];
SQLReview *review = [reviewsArray objectAtIndex:indexPath.row];
cell.usernameLabel.text = (review.user_name == nil) ? #"" : review.user_name;
cell.datetimeLabel.text = (review.datetime == nil) ? #"" : [review.datetime substringToIndex:10];
cell.commentLabel.text = (review.comment == nil) ? #"" : review.comment;
cell.commentLabel2.text = (review.comment == nil) ? #"" : review.comment;
float overallScore = (review.overall == nil) ? 0.0f : [review.overall floatValue];
NSArray *overallImageViewArray = #[cell.overallStarImageView1, cell.overallStarImageView2, cell.overallStarImageView3, cell.overallStarImageView4, cell.overallStarImageView5];
if([selectedIndexPaths containsObject:indexPath]) {
cell.commentLabel.hidden = YES;
cell.commentLabel2.hidden = NO;
CGSize commentLabelComputeSize = [cell.commentLabel2.text sizeWithFont:cell.commentLabel2.font constrainedToSize:CGSizeMake(cell.commentLabel2.frame.size.width, CGFLOAT_MAX) lineBreakMode:cell.commentLabel2.lineBreakMode];
CGFloat commentLabelHeightOffset = (commentLabelComputeSize.height - cell.commentLabel2.frame.size.height > 0) ? (commentLabelComputeSize.height - cell.commentLabel2.frame.size.height) : 0;
cell.commentLabel2.frame = CGRectMake(cell.commentLabel2.frame.origin.x, cell.commentLabel2.frame.origin.y, cell.commentLabel2.frame.size.width, cell.commentLabel2.frame.size.height + commentLabelHeightOffset);
cell.commentLabel2.autoresizingMask = UIViewAutoresizingFlexibleHeight;
cell.commentLabel2.numberOfLines = 0;
} else {
cell.commentLabel.hidden = NO;
cell.commentLabel2.hidden = YES;
}
[CommonUtilities displayStarRatingsWithScore:overallScore starImageViewArray:overallImageViewArray];
return cell;
}
return nil;
}
The isSelected part from heightForRowAtIndexPath does work, and the table cell does visibly expand on tap, but the text remains the same - at least, as tested on iOS 7+ devices.
EDIT: I also logged out the values of cell.commentLabel2.frame, by adding this:
NSLog(#"VenueTabViewController: cellForRow: contains indexpath %#, size: %#", indexPath, NSStringFromCGRect(cell.commentLabel2.frame));
in both the if and else of cellForRowAtIndexPath, and it shows the following:
On first tap:
VenueTabViewController: cellForRow: contains indexpath {length = 2, path = 0 - 1}, size: {{20, 31}, {285, 60.579999999999998}}
On second tap:
VenueTabViewController: cellForRow: contains indexpath {length = 2, path = 0 - 2}, size: {{20, 31}, {285, 21}}
So it does change in size.
What I tried:
I googled this, and found out that [string sizeWithFont:[UIFont systemFontOfSize:15.0f] constrainedToSize:constrainSize lineBreakMode:NSLineBreakByWordWrapping]; has been depreciated. So instead, I replaced the lines relating to it above with:
CGSize labelSize = [text sizeWithAttributes:#{NSFontAttributeName: [UIFont systemFontOfSize:17.0f]}];
CGFloat labelHeight = ceilf(labelSize.height);
Which not only failed to work, it also stopped the cell from expanding, which I thought might be a step backwards.
I also tried adding the following, because why not:
VenueReviewCell *cell = (VenueReviewCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell==nil){
cell = [[[NSBundle mainBundle] loadNibNamed:#"ReviewCell" owner:nil options:nil] objectAtIndex:0];
}
[cell.commentLabel sizeToFit];
But it's still a nope.
Then, I simply replaced commentLabelHeightOffset with 100, just to test if anything will change:
cell.commentLabel2.frame = CGRectMake(cell.commentLabel2.frame.origin.x, cell.commentLabel2.frame.origin.y, cell.commentLabel2.frame.size.width, cell.commentLabel2.frame.size.height + commentLabelHeightOffset);
Nothing happened.
EDIT: Here's what I did that finally gained traction - I removed the AutoLayout on the cells, as per the suggestion of saif. And now, while the cells do expand, and the labels along with it, for some reason I get this:
I checked the code, and the X and Y of the label frame aren't changed (just the frame height) and the text has no "new lines" before the actual text.
Can I have some help please?
Try this, Set the frame to desc label in cell for row(depending on text size), and reload the table view when you want to expand the cell.
In cellForRowAtIndexPath
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID forIndexPath:indexPath];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];
//code to add desc label
}
CGSize suggestedSize = [descriptionText sizeWithFont:descLabel.font constrainedToSize:CGSizeMake(descLabel.frame.size.width, FLT_MAX) lineBreakMode:descLabel.lineBreakMode];
float padding = 20;
[descLabel setFrame:CGRectMake(padding, CGRectGetMaxY(nameLabel.frame), CGRectGetWidth(tableView.frame)-(2*padding), suggestedSize.height)];
if you are using auto layouts in custom cell then
Keep a back up, and uncheck auto layouts
select iPhone in drop down and select Disable size class
If there is a problem with row height,
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
CGSize suggestedSize = [descriptionText sizeWithFont:descLabel.font constrainedToSize:CGSizeMake(descLabel.frame.size.width, FLT_MAX) lineBreakMode:descLabel.lineBreakMode];
float heightOfRow = CGRectGetMaxY(nameLabel.frame)+suggestedSize.height+5; // height of name label(as it is single line supported) + height of desc label + bottom padding
return heightOfRow;
}
Hope this helps
Try autoresizing:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
VenueReviewCell *cell = (VenueReviewCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
cell.commentLabel.autoresizingMask = UIViewAutoresizingFlexibleHeight;
cell.commentLabel.numberOfLines = 0;
return cell;
}
If you want to continue using autolayout:
-set the numberOfLines to '0'
-Implement the following two TableView methods
-(CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
return UITableViewAutomaticDimension;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return UITableViewAutomaticDimension;
}
Working with Self-Sizing Table View Cells Here is a useful reference.
If you're using manual layout then you must set the numberOfLines property of your label to 0, also you will want to call -sizeToFit on the label after setting the text.
You might also need to change some other frames after this accordingly so the label doesn't overlap anything.
If you are using AutoLayout then setting the numberOfLines is still needed but then it depends on your constraints, if you've set the left and right of the label to the super view's left and right then it can infer a maximum width and grow the label vertically.
In any case your screenshot clearly shows that the label is set to have numberOfLines = 1, your cell height looks okay, which is expected since you're calculating that in code with a set width. It's the rendering of the label which is not being triggered. Change numberOfLines to 0 to start with, then in layoutSubviews (if you're doing things manually) you'll want to sizeToFit

Scroll to the last two rows of table

when the table has more records than the screen let you see, and the user scroll to the bottom for the last records in the table, the last two rows are not accessible (just in iOS7, in iOS8 everything is fine). Once the user take the finger from screen, the table goes up, and the last two rows are hidden.
This is one of the method used for tableView but i dont know if this come from here:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString * cellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
// Configure the cell...
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
if (selectionCategMsg == 0)
{
if ([self.tableauMsgReceived count] < 1) {
cell.textLabel.text = NSLocalizedString(#"noMessagesYet", nil); //#"No messages yet !";
}
else
{
cell.textLabel.text = [NSString stringWithFormat:#"%#", [self.tableauMsgReceived objectAtIndex:indexPath.row]];
cell.textLabel.lineBreakMode = NSLineBreakByWordWrapping;
}
}
else
{
if ([self.tableauMsgSent count] < 1) {
cell.textLabel.text = NSLocalizedString(#"noReplyYet", nil);
}
else
{
cell.textLabel.text = [NSString stringWithUTF8String:[NSString stringWithFormat:#"%#", [self.tableauMsgSent objectAtIndex:indexPath.row]].UTF8String];
cell.textLabel.lineBreakMode = NSLineBreakByWordWrapping;
}
}
[cell setAccessoryType:UITableViewCellAccessoryNone];
return cell;
}
Can someone give an advice ? Thank you.
THIS IS THE SOLUTION THAT I FOUND:
// -> SET TABLE FRAME
CGFloat sideMargin = 0;
CGFloat originX = sideMargin;
CGFloat topBottomMargin = 100;
CGFloat originY = topBottomMargin;
// Width based on view size
CGFloat sizeWidth = self.view.bounds.size.width);
// Height based on view size
CGFloat sizeHeight = (self.view.bounds.size.height - topBottomMargin);
self.myTableView.frame = CGRectMake(originX, originY, sizeWidth, sizeHeight);
// <- END SET tableView frame
UITableView has the method scrollToRowAtIndexPath:atScrollPosition:animated:. That method lets you scroll the table view so a given indexPath is visible. Is that what you're looking for?
EDIT:
#Daij-Djan's post is a good theory on what's wrong. If your table view goes off the screen then it will position the last couple of cells inside it's view, but that view won't be visible. You're going to need to do some debugging to figure out what's wrong. You might try setting the table view's layer's borderWidth to a non-zero value so you can see the bounds of the table view.
In your viewDidLoad, add code like this:
myTableView.layer.borderWidth = 1;
myTableView.layer.borderColor= [UIColor redColor].CGColor;
(Where you'd replace "myTableView" with the name of your table view instance variable or property.)
You'll have to import QuartzCore.h in order for the code above to compile:
#import <QuartzCore/QuartzCore.h>

Table View Cell Height using Row Height not Auto Layout Height

I have 3 custom Table View Cell's in a UITableView. I have the the height of one cell perfect, but the other two cells I just want them to use AutoLayout for their height.
This is what I have, does anyone have another idea for the else statement?:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
id model = self.Model[indexPath.row];
if ([model isKindOfClass:[D self]]) {
ListTableViewCell *cellOne = [tableView dequeueReusableCellWithIdentifier:#"1Cell" forIndexPath:indexPath];
if (!cellOne) {
cellOne = [[ListTableViewCell alloc] init];
FR *fD = (FR *)model;
NSString *title = [NSString stringWithFormat:#"%#", fD.title];
NSString *dateString = [self timeSincePublished:fD.pubDate];
NSString *description = [self removeHTMLTags:fD.description];
NSString *link = [NSString stringWithFormat:#"%#", fD.link];
cellOne.labelHeadline.text = title;
cellOne.labelDescription.text = description;
cellOne.labelPublished.text = dateString;
}
// Make sure the cell's frame is updated
[cellOne setNeedsLayout];
[cellOne layoutIfNeeded];
CGFloat heightOne = [cellOne.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
return heightOne + 2;
} else {
// This is where I need help for other 2 custom cells to just use AutoLayout height
return tableView.rowHeight;
}
Right now, return tableView.rowHeight is returning the hardcoded height that is set in the storyboard, regardless of how much is actually in the cell.
It should ignore that height and just use AutoLayout.
Do you know a way to do that? Thanks! Will gladly post any extra info if needed-
With auto layout you don't use heightForRowAtIndexPath.
Instead you can use something like this:
self.tableView.estimatedRowHeight = 44.0;
self.tableView.rowHeight = UITableViewAutomaticDimension;

UILabel upon a few UITableViewCells

Am I able to create a UILabel that is layouted upon many UITableViewCells?
I'm trying to make something like (that is just one section of my UITableView, each section can have one or more rows):
---------------------------------------------
| Multi-lined label | row1 values |
| with some useless | row2 values |
| text | row3 values |
---------------------------------------------
I managed to create a UILabel (in the first row of a section) that is multi-lined and is not clipping to bounds. That works really well (it was a bit tricky to count each sections row heights, but doable) besides one case: when I'm scrolling UITableView from bottom to top - UITableView renders last row (without UILabel) so it has "no evidence" of having UILabel (because it is maintained in the first row of section). Can I force some kind of relayouting first cell in section? I tried reloadRowsAtIndexPaths:withRowAnimation: with first row in each section whenever I layouted not first cell in section but it gave me layouting errors that I really do not understand. Or maybe there is another idea to do so?
-- EDITED
To be clear: I have a custom UITableViewCell with an IB view, it has a few labels that each row consist of and a label named labelName that I want to be "multi-lined" along rows in that section. LabelName.text is empty for each row besides first one in each section.
I am adding somescreenshots:
Good screenshot - when I am scrolling to bottom I'm getting proper effect:
Bad screenshot - when I am scrolling up, UITableView renders last row of section firstly, and afterwards renders upper rows - that gives effect of cut label (because multi-line label is in the first row)
I am not sure if code here will add anything to question - it is rather simple and almost whole logic is in tableView:heightForRowAtIndexPath. I can only present how do I create custom UITableViewCell:
CustomTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:[CustomTableViewCell reuseIdentifier]];
if (cell == nil) {
cell = [[CustomTableViewCell alloc] initWithOwner:self];
cell.clipsToBounds = NO;
cell.labelName.clipsToBounds = NO;
cell.contentView.superview.clipsToBounds = NO;
}
-- EDIT 2
Here is most of the code:
- (void) reloadData
{
NSUInteger index = 0;
for (NSDictionary *object in self.list) {
CGFloat height = [[object objectForKey:#"name"] sizeWithFont:self.labelFont constrainedToSize:self.labelSize].height;
[self.labelHeights addObject:NSNumberFloat(ceilf(height))];
index++;
}
[self.tableView reloadData];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSDictionary *object = [self.list objectAtIndex:indexPath.section];
CGFloat height = [[self.labelHeights objectAtIndex:indexPath.section] floatValue];
NSUInteger count = [[object objectForKey:#"list"] count];
CGFloat cellHeight = 30.f;
if((indexPath.row + 1) == count){
cellHeight = MAX(8.f + height - 30.f * indexPath.row, 30.f);
}
return cellHeight;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [self.list count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [[[self.list objectAtIndex:section] objectForKey:#"list"] count];
}
- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSDictionary *person = [self.list objectAtIndex:indexPath.section];
NSDictionary *object = [[person objectForKey:#"list"] objectAtIndex:indexPath.row];
CustomTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:[CustomTableViewCell reuseIdentifier]];
if (cell == nil) {
cell = [[CustomTableViewCell alloc] initWithOwner:self];
cell.backgroundColor = [UIColor clearColor];
cell.userInteractionEnabled = NO;
cell.clipsToBounds = NO;
cell.labelName.clipsToBounds = NO;
[cell.contentView.superview setClipsToBounds:NO];
}
if(indexPath.row == 0){
cell.labelName.text = [person objectForKey:#"name"];
CGFloat height = [[self.labelHeights objectAtIndex:indexPath.section] floatValue];
cell.labelName.numberOfLines = (int)(height / self.fontSizeHeight);
cell.labelName.frame = CGRectChangeHeight(cell.labelName.frame, height);
}
else{
cell.labelName.text = #"";
}
CGFloat cellHeight = [self tableView:self.tableView heightForRowAtIndexPath:indexPath];
cell.borderTop.hidden = YES;
cell.borderBottom.hidden = YES;
cell.borderBottomSmall.hidden = NO;
if(indexPath.row == 0){
cell.borderTop.hidden = NO;
}
if(indexPath.row + 1 == [[person objectForKey:#"list"] count]){
cell.borderBottom.hidden = NO;
cell.borderBottom.frame = CGRectChangeY(cell.borderBottom.frame, cellHeight - 1.f);
cell.borderBottomSmall.hidden = YES;
}
cell.labelDate.text = [object objectForKey:#"date"];
cell.labelPremium.text = [[object objectForKey:#"premium"];
return cell;
}
-- PARTIAL ANSWER
I managed to create a hack, that makes multi-line UILabel visibile when scrolling bottom to up at some point:
- (void) scrollViewDidScroll:(UIScrollView *)scrollView
{
NSArray *cells = [self.tableView visibleCells];
UITableViewCell *cell = [cells objectAtIndex:0];
[cell.superview bringSubviewToFront:cell];
}
I noticed that the part of the UILabel is covered by a row thats below of the UILabels row and that hack makes it would be properly displayed. But it has a drawback, when scrolling slowly from bottom to top it generates a flicker when label is created (part of it should be visible before real creation of UILabel).
Up mentioned answers are not solutions, but "hacks".
In the cell == nil block should be only the initialization.
You should not add any subviews in cell in cellForRowAtIndexPath.
The reason is simple: I will reuse a cell with some labels already added and add a new label.
Either use the default cell.textLabel, either create a subclass for UITableViewCell, with a
-(void)setData:(dictionary or string)object;
and in implementation just set the proper data to proper UI controls.
Add/create controls either in init method in the subclass, or in IB/Storyboard.
Call the dictionary or string should be picked in correspondence to indexPath, so you will always get proper data for proper cell at proper indexPath.
Try This
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellId = #"cellId";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellId];
if (cell==nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellId];
}
for (UIView *subview in [cell.contentView subviews]) {
[subview removeFromSuperview];
}
/// your UI on cell goes here
return cell;
}

IOS Tableview custom cell with dynamic label height

I have trying to figure out this for quite some time :
I have a custom cell in tableview which has two labels one below other. The top label can be of one line or two line max. The bottom label is restricted to just one line.
The top label will always be there but the bottom label will be there for some cells and my not be there for some other cells.
I need a way to figure out how to arrange these labels centered vertically. I tried making the top label dynamic by using cell.label1.numberOfLines = 0; But then the label1 is not really restricted to 2 lines.
I tried to center these labels vertically by computing the height of first label and then arranging both labels centered.
If I restrict the number of lines to 2 using xib, then the height for first label always computes as 2 lines, even if the label consumes 1 line. One issue always which I see is if I use [cell.label1 sizeToFit]; then while scrolling the table the label always seem to change the text shown . The text shown is always for the respective label but the text sometimes wraps midway sometimes uses the full line.
Here is my code for reference :
CustomCell1 *cell = (CustomCell1 *)[self.tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"CustomCell1" owner:self options:nil];
cell = [nib objectAtIndex:0];
cell.label1.lineBreakMode = UILineBreakModeWordWrap;
cell.label1.numberOfLines = 0;
cell.label1.tag = [indexPath row];
}
cell.label1.text = [[responseArray objectAtIndex:[indexPath row]] text];
if([[[responseArray objectAtIndex:[indexPath row]] isDone] isEqualToString:#"N"]) {
cell.label2.text = #"";
} else {
cell.label2.text = #"Done";
}
//[cell.label1 sizeToFit];
CGSize label1Size = [cell.label1 frame].size;
CGFloat label1Height = label1Size.height;
CGRect label1Frame = cell.label1.frame;
int numLines = (int)(label1Height/cell.label1.font.leading);
CGSize label2Size = [cell.label2 frame].size;
CGFloat label2Height = label2Size.height;
CGRect label2Frame = cell.label2.frame;
if(numLines > 1) {
if([cell.label2.text isEqualToString:#""]) {
//if label2 == "" then center label1
label1Frame.origin.y = cellHeight/2 - label1Height/2;
cell.label1.frame = label1Frame;
} else {
label1Frame.origin.y = 12;
cell.label1.frame = label1Frame;
label2Frame.origin.y = 52;
cell.label2.frame = label2Frame;
}
} else {
if([cell.label2.text isEqualToString:#""]) {
CGRect frame = cell.label1.frame;
frame.origin.y = cellHeight/2 - label1Height/2;
cell.label1.frame = frame;
} else {
label1Frame.origin.y = cellHeight/2 - label1Height/2;
cell.label1.frame = label1Frame;
label2Frame.origin.y = cellHeight/2;
cell.label2.frame = label2Frame;
}
}
Please help me IOS gurus with your suggestions.
It would be better to move the resizing calculations to layoutSubviews.
//CustomCell.m
- (void)layoutSubviews{
CGRect label1Frame = self.label1.frame;
//Calculate the size of label 1
CGSize label1Size = [self.label1.text sizeWithFont:[self.label1 font]
constrainedToSize:CGSizeMake(label1Frame.size.width,42.0f)
lineBreakMode:NSLineBreakByTruncatingTail];
label1Frame.size.height = label1Size.height;
CGRect label2Frame = self.label2.frame;
//Calculate the size of label 2
CGSize label2Size = [self.label2.text sizeWithFont:[self.label2 font]
constrainedToSize:CGSizeMake(label2Frame.size.width,21.0f)
lineBreakMode:NSLineBreakByTruncatingTail];
label2Frame.size.height = label2Size.height;
//Total height of labels
CGFloat totalHeight = label1Frame.size.height+label2Frame.size.height+5.0f;
//For centering half of difference of two labels with cell
label1Frame.origin.y = (self.frame.size.height - totalHeight)/2.0f;
self.label1.frame = CGRectIntegral(label1Frame);
label2Frame.origin.y = label1Frame.origin.y+label1Frame.size.height+5.0f;
self.label2.frame = CGRectIntegral(label2Frame);
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
CustomCell1 *cell = (CustomCell1 *)[self.tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"CustomCell1" owner:self options:nil];
cell = [nib objectAtIndex:0];
cell.label1.lineBreakMode = UILineBreakModeWordWrap;
cell.label1.numberOfLines = 2;
cell.label1.tag = [indexPath row];
}
cell.label1.text = [[responseArray objectAtIndex:[indexPath row]] text];
if([[[responseArray objectAtIndex:[indexPath row]] isDone] isEqualToString:#"N"]) {
cell.label2.text = #"";
} else {
cell.label2.text = #"Done";
}
return cell;
}

Resources