I'm using this code to resize the labels that maintains the titles of my cells. The problem is that the cells labels are not resizing until I scroll the table. Cells need to disappear to resize their labels correctly. What can I do to get all the cells labels well resized without having to scroll previously?
Thanks for reading.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
ExampleTableViewCell *cell = (ExampleTableViewCell *)[tableView dequeueReusableCellWithIdentifier:#"ExampleTableViewCell"];
if (cell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"ExampleTableViewCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
cell.title.text = [self.test objectAtIndex:[indexPath row]];
//Calculates the expected size based on the font and linebreak mode of the label.
CGSize maximumLabelSize = CGSizeMake(200, [UIScreen mainScreen].bounds.size.width);
CGSize expectedLabelSize = [cell.title.text sizeWithFont:cell.title.font constrainedToSize:maximumLabelSize lineBreakMode:cell.title.lineBreakMode];
// Adjusts the label the the new height.
CGRect newFrame = cell.title.frame;
newFrame.size.height = expectedLabelSize.height;
cell.title.frame = newFrame;
return cell;
}
Try to write the same code in
willDisplayCell method of UItableViewController
Another approach is .... in your ExampleTableViewCell class implement
- (void)layoutSubviews{
}
set your title's frame in above function. It should work
you must implement the method heightForRowAtIndexPath and return the height of cell then your problem solved :-)
I found Matt Long's solution really helpful (http://www.cimgf.com/2009/09/23/uitableviewcell-dynamic-height/).
Related
I tried to use autolayout in custom uitableviewcell
And tried to implement the dynamic height according to this SO topic
Using Auto Layout in UITableView for dynamic cell layouts & variable row heights
But my cell is created by xib file. So the method is somewhat different
Here is my code in heightForRowAtIndexPath
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
myDataItem *item= [[data items] objectAtIndex:[indexPath row]];
CustomCell *cell = [self.offscreenCells objectForKey:#"CustomCell"];
if (!cell) {
cell = [CustomCell alloc] init];
[self.offscreenCells setObject:cell forKey:#"CustomCell"];
}
[cell.commentView setText:item.comment];
[cell.displayNameView setText:item.displayNameOfItemOwner];
[cell.timeAgoView setText:item.timeAgo];
[cell.imageView setImage:[UIImage imageNamed:#"sis_profile_placeholder"]];
cell.bounds = CGRectMake(0.0f, 0.0f, CGRectGetWidth(tableView.bounds), CGRectGetHeight(_prototypeCell.bounds));
[cell setNeedsLayout];
[cell layoutIfNeeded];
CGFloat height = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
return height+1; }
And the height that I got from [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize] is alway "nil"
"
When I tried to debug ,I found that all subviews of my customcell are "nil" but the cell itself is not "nil". This might because the customCell of mine is made by nib and when I do [[CustomCell alloc] init] the cell is not fully created.
But I did tried to change method to cell = [_tableView dequeueReusableCellWithIdentifier:#"CustomCell"];
The result is still the same. Every subview is nil . This make the height return to be zero and the make my tableView display incorrectly. Are there any way to solve this ?
I tried to make these upon AutoLayout .Actually, in the previous version ,that I didn't use AutoLayout and calculate the cell height manually .It did work perfectly. Anyway, I just want to tried AutoLayout.
Please help .Thanks in advance
Here is my solution
I alloc new cell by
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"CustomCell" owner:self options:nil];
// Grab a pointer to the first object (presumably the custom cell, as that's all the XIB should contain).
cell = [topLevelObjects objectAtIndex:0];
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
myDataItem *item= [[data items] objectAtIndex:[indexPath row]];
CustomCell *cell = [self.offscreenCells objectForKey:#"CustomCell"];
if (!cell) {
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"CustomCell" owner:self options:nil];
// Grab a pointer to the first object (presumably the custom cell, as that's all the XIB should contain).
cell = [topLevelObjects objectAtIndex:0];
[self.offscreenCells setObject:cell forKey:#"CustomCell"];
}
[cell.commentView setText:item.comment];
[cell.displayNameView setText:item.displayNameOfItemOwner];
[cell.timeAgoView setText:item.timeAgo];
[cell.imageView setImage:[UIImage imageNamed:#"image"]];
cell.bounds = CGRectMake(0.0f, 0.0f, CGRectGetWidth(tableView.bounds), CGRectGetHeight(_prototypeCell.bounds));
[cell setNeedsLayout];
[cell layoutIfNeeded];
CGFloat height = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
return height+1; }
As far as I know, under iOS 8 the proposed solution is not going to work for cells with multiline labels because systemLayoutSizeFittingSize will not take into account the desired cell width (simply put, it will try to layout the label into a single line, thus making the cell wider than it should).
I managed to solve this issue by installing a width constraint in cell's contentView instead of setting the cell bounds. Remember to uninstall such constraint right after calling systemLayoutSizeFittingSize:.
I'm trying to have a label in a UITableViewCell that can span two lines, but if there is only one line align it vertically to the first line.
The code to work out the label height (below) seems to work, but the label isn't getting relaid/repainted. If I scroll the cell off the view and back again, the label has the correct height.
I have tried [cell setNeedsLayout], [cell setNeedsDisplay], [titleLabel setNeedsLayout] and [titleLabel setNeedsLayout, and no combination has worked.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"ItemCell" forIndexPath:indexPath];
Item *item = (self.items)[indexPath.section][indexPath.row];
UILabel *titleLabel = (UILabel *)[cell viewWithTag:100];
titleLabel.text = item.title;
titleLabel.backgroundColor = [UIColor redColor];
// Some titles span two lines, so resize to fit the new content.
CGRect textRect = [titleLabel.attributedText boundingRectWithSize:CGSizeMake(titleLabel.frame.size.width, CGFLOAT_MAX) options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading) context:nil];
CGRect labelRect = CGRectIntegral(CGRectMake(titleLabel.frame.origin.x,
titleLabel.frame.origin.y,
titleLabel.frame.size.width,
textRect.size.height));
NSLog(#"%#, %f", titleLabel.text, labelRect.size.height); // This logs out the correct height
titleLabel.frame = labelRect;
return cell;
}
please try my suggestion. may be it will help you with the reusability of cell in UITableview. Please Check the following points in you code:
What to do if you cell == nil while redrawing UITableView in iPhone. thats why you have to make condition like below for reusability of UITableViewCell.
// Get table View Cell
static NSString *CellIdentifier = #"ItemCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray *nib;
nib = [[NSBundle mainBundle] loadNibNamed:CellIdentifier owner:self options:nil];
cell = (UITableViewCell *) [nib objectAtIndex:0];
}
Please test it and let me know.
Turns out I'm using auto layout, which means I can't set the frame directly. Instead I need to add a height constraint and connect it to an IBOutlet on my UITableViewCell subclass.
STEP 1 - this is working fine
I have UITableView that loads custom UITableViewCells
STEP 2 - this is kinda works
I change the UITableViewCell height so that all the data contained in the cell within a UITextView is visible
I manage to get the UItextView data and resize it by using the following code:
UITextView *dummy = [[UITextView alloc] init];
dummy.font = [UIFont systemFontOfSize:14];
dummy.text = cell.textView.text;
CGSize newSize = [dummy sizeThatFits:CGSizeMake(270.0f, 500.0f)];
//get the textView frame and change it's size
CGRect newFrame = cell.textView.frame;
newFrame.size = CGSizeMake(270.0f, fmaxf(newSize.height, 60));
cell.textView.frame = newFrame;
//resize the cell view I add +95 because my cell has borders and other stuff...
CGRect cellFrame = CGRectMake(0, 0, 320, newFrame.size.height+95);
cell.cellView.frame = cellFrame;
I then manage to set the UITableViewCell height using the delegate function heightForRowAtIndexPath:
Now when I run the code and scroll up and down the table cells the behavious isn't always as expected... i.e the cell size isn't always the right size, but if I scroll up and down it sometimes loads up the right size again.
I am thinking that perhaps the dequeueReusableCellWithIdentifier is the issue
cellIdentifier = #"tableCell";
ctTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
Since I am recycling cells of different size with the same identifier...
Can anybody give me some guidelines on how best to solve this issue?
Thanks!!!
I would start by adding UITextView dynamically inside cellForRowAtIndexPath method. assumptions(data array contains the content to be displayed inside cell)
// Defines
#define CELL_TEXTVIEW_WIDTH = 320
#define CELL_TEXTVIEW_HEIGHT = 9999
#define PADDING = 5
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"tableCell";
ctTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
if(cell == nil){
cell = [[tableView alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
NSString *_data = [data objectAtIndex:indexPath.row];
CGSize _data_contentsize = [_data sizeWithFont:[UIFont systemFontOfSize:14] constrainedToSize:CGSizeMake(CELL_TEXTVIEW_WIDTH, CELL_TEXTVIEW_HEIGHT) lineBreakMode:NSLineBreakModeWordWrap];
UITextView *dummy=[[UITextView alloc] initWithFrame:CGRectMake(5, 5, 290, _data_contentsize +(PADDING * 2))];
// add Font and text color for your textview here
[cell.contentView addSubview:dummy];
return cell;
}
After this calculate the height of the cell under heightForRowAtIndexPath method.
have you implemented following method ?
(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
https://developer.apple.com/library/ios/documentation/uikit/reference/UITableViewDelegate_Protocol/Reference/Reference.html#//apple_ref/occ/intfm/UITableViewDelegate/tableView:heightForRowAtIndexPath:
you should set height for each row , if they are different from each other
I'm trying to change the height of an UITextView which I have in a custom made Cell for my tableView.
The 'OverviewCell' is an identifier of this custom cell in a nib and also the UITextView 'postIntro' is dragged into the nib.
Sadly enough the height is not changing, only after i scrolled the height is changed. The cells which are visible without scrolling are just the default height from the nib.
When i try to change the height of the 'postImage' the same problem happens.
This is my code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"OverviewCell";
OverviewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
Post *post = [self.posts objectAtIndex:[indexPath row]];
if(!cell)
{
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"OverviewCell" owner:nil options:nil];
for(id currentObject in topLevelObjects)
{
if([currentObject isKindOfClass:[OverviewCell class]])
{
cell = (OverviewCell *)currentObject;
break;
}
}
}
[[cell postImage] setImage:[UIImage imageWithData:post.image]];
[[cell postTitle] setText:post.title];
[[cell postIntro] setText:post.intro];
// Resize the intro textview so the text fits in.
CGRect frame = cell.postImage.frame;
frame.size.height = 20; //cell.postIntro.contentSize.height;
[cell.postIntro setFrame:frame];
NSLog([NSString stringWithFormat:#"Height of textView on indexpath %i is set to %f", indexPath.row ,cell.postImage.frame.size.height]);
return cell;
}
Any other suggestions to my code is welcome...
I finally got it working by changing the constraint of the UITextview in code.
I've created and IBOutlet which is attached to the constraint of the UITextview.
IBOutlet NSLayoutConstraint * postContentHeightConstraint;
After that I've set the constraint height to the specified height for the cell (contentSize).
self.postContentHeightConstraint.constant = self.postContent.contentSize.height;
After setting the new height to the constraint, call the layoutIfNeeded function on the UITextView
[self.postContent layoutIfNeeded];
Implement tableView:heightForRowAtIndexPath: in your table view delegate.
Update: To update the height of the UITextView after it has been created, call [cell.postIntro setNeedsLayout] after setting the frame
For changing the height of the UITextView, call
[tableView beginUpdates];
[tableView endUpdates];
after setting the new dimensions for the UITextView.
Questions this, and this will help with your problem.
Hope the answer helped!
I have a UITableView that uses prototype cells. The cells have a custom class called dataCell. The custom cells also have three UILabels:idLabel, contLabel, and expLabel. The cells properly resize based on the amount of text in expLabel; however, I cannot get the label itself to resize. Some labels resize when I scroll down; however, they also revert to showing only two lines and omitting text when I scroll back up. Here is my code
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
dataCell *cell = (dataCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// the rest of your configure cell
// First Cell Label
[cell.idLabel setText:[idData objectAtIndex:indexPath.row]];
cell.idLabel.numberOfLines = 0;
// Second Cell Label
[cell.contLabel setText:[conData objectAtIndex:indexPath.row]];
cell.contLabel.numberOfLines = 0;
// Third Cell Label
[cell.expLabel setText:[expData objectAtIndex:indexPath.row]];
cell.expLabel.numberOfLines=0;
CGSize expectedLabelSize = [cell.expLabel.text sizeWithFont:cell.expLabel.font constrainedToSize:CGSizeMake(220, FLT_MAX) lineBreakMode:cell.expLabel.lineBreakMode];
cell.expLabel.frame=CGRectMake(cell.expLabel.frame.origin.x, cell.expLabel.frame.origin.y, expectedLabelSize.width, expectedLabelSize.height);
return cell;
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath {
dataCell *cell = (dataCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
CGSize maximumLabelSize = CGSizeMake(220, FLT_MAX);
[cell.expLabel setText:[expData objectAtIndex:indexPath.row]];
CGSize expectedLabelSize = [cell.expLabel.text sizeWithFont:cell.expLabel.font constrainedToSize:maximumLabelSize lineBreakMode:cell.expLabel.lineBreakMode];
if (expectedLabelSize.height<43) {
expectedLabelSize.height=43;
}
return expectedLabelSize.height; }
Any help would be much appreciated
If you are using a storyboard and a UITableViewCell then you can just change the auto resizing mask, but if you are doing it programmatically then you will have to set the calculate the text width and height and reset the frame of the labels,
UILabel* label = [[UILabel alloc] init];
UIFont* font = label.font;
CGSize maxContentSizeForText = CGSizeMake(maxTextWidth, maxTextHeight);
CGSize stringTextSize = [string sizeWithFont:font constrainedToSize:maxContentSizeForText lineBreakMode:NSLineBreakByWordWrapping];
[label setFrame:CGRectMake(xPosition, yPosition, stringTextSize.width, stringTextSize.height);
[label setNumberOfLines:1000];
your label is probably a property from a xib file or storyboard, and the number of lines is just saying that you want the label to get really really big, since we can't say "infinite" i just generally use 1000 indicating 1000 lines of text maximum