Dynamic sized labels inside a table not refreshing in ios - ios

My table has cells which have several labels. I want one of these labels to fit its size so text begins right below the Title (remember that Labels align text vertically unless you fit its container).
Problem is, the very first time the table is loaded all labels' texts are succesfully populated but label sizes don't actually graphically apply until the NEXT time a refresh is asked. (if I ask for a reloadData with the exact same information, the labels' sizes work flawlessly).
This is some of my cellForRowAtIndexPath code:
cell.body.text = user.message;
[cell.body sizeToFit];
The only solution I've found so far is double calling [table reloadData] but this is an ugly solution. Any way I can fix this?
Edit: Previous code was a summary, I'll show the whole code here as requested:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
TwitterTweetCell *cell = [tableView dequeueReusableCellWithIdentifier:#"TwitterTweetCell"];
// Populate cell
TweetModelData *tweet = [self.twitterModelData.tweets objectAtIndex:[indexPath item]];
cell.tweetName.text = tweet.user;
cell.tweetChannel.text = tweet.userName;
cell.tweetBody.text = tweet.message;
[cell.tweetBody sizeToFit];
return cell;
}
Regarding cell size, everything is working ok. Depending on the size of the message each cell has a different size which was pre-calculated before.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return ((TweetModelData *)[self.twitterModelData.tweets objectAtIndex:[indexPath item]]).tweetHeight + 30.0f;
}

I finally found it. Don't know the reason, but it seems disabling "Use autolayout" on my storyboard fixed it.
I'm guessing auto-layout was overwriting the layout changes I was applying so they had no effect until the next data reload.

Related

UILabel size changes when UITableView scroll

I have an old objective c project which has an UITableView. All the UILabels in each cells have been created by code. This is my cellForRowAtIndex
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *metadataListTableIdentifier = #"MetadataListTableViewCell";
MetadataTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:metadataListTableIdentifier];
NSMutableDictionary *dict = [theListData objectAtIndex:indexPath.row];
[MetrixListScreenManager setCellDataDictionary:dict];
if (cell == nil || cellReloadCount <= cellReloadLimit) {
cell = [MetrixListScreenManager generateCellForListScreen:self withReuseIdentifier:metadataListTableIdentifier andScreenId:self.screenId];
cellReloadCount++;
}
[SkinApplicationUITableViewController applySkinColorToRelevantControlsForCell:cell];
[MetrixListScreenManager populateCellDataForListScreenId:self.screenId usingCell:cell andDataRow:dict];
return cell;
}
According to this implementation, in generateCellForListScreen method, all the labels are creating by giving fixed height and width. Then in populateCellDataForListScreenId method all the texts are setting for previously created UILabels. Now we want to make to adjust cell height according to the content height. So what I did was in generate cell method I got the text height and replace the predefined height with that. But my problem is when I scroll some UILabel's height getting increased and rest of the UILabels are going beyond the cell bottom margin. What is the proper way to do this? Please help me.
Thanks

self.tableView reloadData is not working to vertically center my label text

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"MyCell";
MyCustomCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (cell == nil)
cell = [[MyCustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
Movie *movie = [self.movies objectAtIndex:indexPath.row];
cell.title.text = movie.title;
cell.subtitle.text = movie.subtitle;
cell.subtitle.numberOfLines = 0;
[cell.subtitle sizeToFit];
return cell;
}
I am calling reloadData from two places. One is from the end of a loadInitialData function, which is called from viewDidLoad.
A second one is being called from viewDidAppear, although this is inconsequential to my problem, because it existed before it and exists without it.
I initially load 3 rows of sample data, with titles and subtitles. Now what happens is my subtitle text is vertically centered when this window first launches. If I grab the table and scroll is high up, all of a sudden my [cell.subtitle sizeToFit] goes into action, and my text goes to the top vertically, which is desired.
So my issue is... why is the text vertically centered from the beginning? reloadData doesn't work either. When I return from adding a new row, all rows but the newly added row are vertically aligned to top as they should. The new row is incorrectly vertically centered.
Why doesn't this work? Everything seems good. New data is added etc. Via NSLog statements, I have verified numberOfRowsInSection is immediately called after reloadData is called.
So why does the aligning of the text vertically to the top not work?
Thanks!
This is probably because the UITableViewCell has not yet been layed out and so it does not have a size yet. Try doing the sizeToFit in this UITableViewDelegate method
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
I am not sure this will work, but it worth trying.
Add [cell setNeedsLayout]; before you return the cell so it will layout the cell before presentation.

UITextView setFrame not woking in UITableViewCell

In my UITableViewController Subclass
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"TextCell";
TextCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
[cell setContentText:[texts objectAtIndex:indexPath.row]];
return cell;
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
return 200;
}
In my UITableViewCell Subclass
-(void)setContentText:(NSString*)text{
[self.cellText setText:text];
CGRect frame=self.cellText.frame;
frame.size.height=[self textViewHeightForText:text andWidth:frame.size.width];
[self.cellText setFrame:frame];
}
self.celltext is created in storyboard
Problem like this:
First three of the textViews doesn't change their frame.
But when I scroll it down,the textViews below changed their frame.
Scroll back to top again,first three textView changed their frame finally.
Why the first three textViews doesn't change their frame at first?
And how to solve the problem?
The problem is that in cellForRowAtIndexPath:, your cell's frame is not set yet. And later, when it is set, you don't adjust the frame again.
Like all layout in UIView subclasses, the best place to set frames is inside the layoutSubviews method. This method will get called at the right time to set the subviews' frames. Don't forget to call [super layoutSubviews] at the beginning.
Note that it may get called multiple times per instance (it may get called on rotation, or when the status bar frame changes, for example). Therefore, try to keep expensive operations out of here. Since calculating text sizes can be expensive, you may want to cache the result the first time you use it.

UILabel in a UITableViewCell With Dynamic Height

I'm having some problems implemented dynamic row heights in a UITableView - but it isn't the cells that I'm having a problem with, its the UILabel inside of the cell.
The cell just contains a UILabel to display text. My tableView:heightForRowAtIndexPath: is correctly resizing each cell by calculating the height of the label that will be in it using NSString's sizeWithFont: method.
I have a subclass of UITableViewCell that just holds the UILabel property that is hooked up in storyboard. In storyboard I've set its lines to 0 so it will use as many lines as it needs, and I've set its lineBreak to Word Wrap.
Here is how I'm setting up the cells:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
ExpandCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
SomeObject *object = self.tableObjects[index.row];
cell.myLabel.text = [object cellText];
[cell.myLabel sizeToFit];
return cell;
}
When I build this, I get my table view with the cell's all sized to the correct height for their content, but the labels are all 1 line that just runs off the side of the cells. However, if I scroll the table so cell's leave the screen, and then scroll back to them, their label will be resized correctly and the cell will look how I expected it to initially.
I have also attempted calculating the labels frame with the same method I'm calculating the row height with, and I get the same behavior - it doesn't draw correctly until it scrolls off of the screen and back on again.
I have found two ways to work around this, and neither are acceptable solutions.
First, if in viewDidAppear: I call reloadData on my tableview, the cells and labels draw themselves correctly the first time. This won't work for my situation because I will be adding and removing cells to this table, and I don't want to call reloadData every time a cell is added.
The second workaround seems very strange to me - if I leave the font settings at the default System Font 17 on the UILabel, the cells draw themselves correctly. As soon as I change the font size, it reverts to its behavior of not drawing a label correctly until it leaves the screen and comes back, or gets reloadData called on the tableView.
I'd appreciate any help with this one.
I ended up resolving this by alloc/init'ing the label in cellForRowAtIndexPath. I'm not entirely sure why this is a solution - but it appears the problem I was experiencing has to do with how storyboard (or when, perhaps?) creates the objects within the cell. If I alloc/init the label in the cell in cellForRowAtIndexPath, everything loads and sizes correctly.
So... my current fix is to check if the cell has my custom label in it. If it doesn't, I alloc/init the label and put it in the cell. If it does have one, as in its a cell that's been dequeued, then I just set the text in the label that is already there.
Not sure if its the best solution, but its working for now.
I ended up resolving this by unchecking the AutoSizing checkbox in IB. It is unclear why auto-layout was causing this problem.
I ran over the same problem and I end up solving it by calling [cell layoutIfNeeded] before return the cell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
ExpandCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
SomeObject *object = self.tableObjects[index.row];
cell.myLabel.text = [object cellText];
[cell layoutIfNeeded];
return cell; }

iPhone + UITableView

I am having UITableView in my application, I want to do formatting of it, like change the height of rows in table, change the font and colors of text in cells etc.
It sounds like you should read A Closer Look at Table-View Cells in Apple's Table View Programming Guide for iOS.
Changing the Text Colour and Font
If you're using a standard table view cell, you can customise the text colour and font of its textLabel (or detailLabel) label in the tableView:cellForRowAtIndexPath: data source method:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
/* Cell initialisation code... */
/* Configure Cell */
[[cell textLabel] setTextColor:[UIColor grayColor]];
[[cell textLabel] setFont:[UIFont fontWithName:#"Marker Felt" size:22]];
return cell;
}
Changing the Height of a Row
If every row is going to be the same height, you should set the rowHeight property of your UITableView:
[tableView setRowHeight:42];
If the rows are going to have variable heights, then you can use the tableView:heightForRowAtIndexPath: delegate method of UITableView:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
CGFloat height = 42;
if ([indexPath row] == 4) {
height = 21;
}
return height;
}
If you want to completely change the look of your table view cells, you might want to look at Matt Gallagher's Easy custom UITableView drawing article, as suggested by #mfu. However, make sure you know exactly what you're doing if you start going this far—most of the time you will want to stick to Apple's default styles.
Your question is rather general.
You can refer to very nice article here to get some basic idea on how you can write custom table view 'easy custom uitableview drawing'
You should look at subclassing UITableViewCell and with that new subclass you can have anything you want inside the cell - other views, buttons, labels, etc.
Apple has many good samples of this. See this for a list of samples.

Resources