tl;dr: Can I cause the detailTextLabel to have its size updated by the auto layout system in iOS on a value change?
Has anyone else had issues with the detailText label within an UITableViewCell since iOS 8?
I have a table which both text and detail strings. Initially detail text is an empty string (@""). After performing a storyboard segue to an edit screen, I return with a new value for the detail text and update it. I attempt to reload the table in viewWillAppear so that the value is present immediately upon returning to the previous view.
Once the table view is visible again, the table cell has shifted the text field up to make room for the detail text, but no detail text is displayed. The text does not display until I return to the edit screen, and come back a second time.
What I've done to troubleshoot: It looks as thought the auto layout for the detail text label isn't correctly updating as I think it should, and logging the size and makeup of the detailTextLabel's frame confirms this.
I am able to force the text to update by running [table reloadData] within viewDidAppear, however that leaves me with a flicker effect I don't like, and looks unprofessional.
Edit: Additional things I've done: I've also forced the detailTextLabel to re-size itself using [cell.detailTextLabel sizeToFit]. This causes it to display, but offset in an odd way in the cell. After going to the edit page again, the detailTextLabel fixes it's position.
I've created a simple project as a github repo, to show exactly what I'm dealing with:
https://github.com/acidaris/ios8_table_issue
The main code of the view controller I'm using is also below.
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self.table reloadData];
}
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section {
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:@"CellIdentifier"];
cell.textLabel.text = @"This is a test";
cell.detailTextLabel.text = self.value;
CGRect frame = cell.detailTextLabel.frame;
NSLog(@"detailTextLabel x=%f y=%f width=%f height=%f",
frame.origin.x,frame.origin.y,frame.size.width,frame.size.height);
return cell;
}
The cell is prototyped within a StoryBoard, and so the cell selected by dequeueReusableCellWithIdentifier: is always defined. Additionally, the cell type within the storyboard is set to subtitle, and it does display if the initial value is defined.
If anyone could help me figure this out, I would be incredibly grateful.
Partial Solution
If you are sub-classing UITableViewCell, you can modify the frame for the detailTextLabel when the layout is done. This is what I've done, and it seems to have worked, but on the 6 plus, I get a weird dividing line between the textLabel and the detailTextLabel. edit: (I have adjusted for this.) I don't like this solution, but thus far it's the best I've come across. It doesn't update after presenting the view, and is relatively simple. As I said above, I will continue to look for a better solution.
- (void)layoutSubviews {
[super layoutSubviews];
CGRect textFrame = self.textLabel.frame;
[self.detailTextLabel sizeToFit];
CGFloat x = textFrame.origin.x;
CGFloat y = textFrame.origin.y + textFrame.size.height;
CGSize detailSize = self.detailTextLabel.frame.size;
CGRect newFrame = CGRectMake(x, y, detailSize.width, detailSize.height);
self.detailTextLabel.frame = newFrame;
}
I've also updated my Github project to reflect my current solution. Edit3: This doesn't work perfectly, as it has wrong values for truly auto layout frames, but it works for my uses for the moment.
Edit 4: I've updated my layoutSubviews function to be smarter. It will size to fix the content within the label, and position the label appropriately within the x/y coordinates in relation to the text label.
Having the same problem. My solution was to call
[cell layoutSubviews]
before returning the cell at the end of-tableView:cellFForRowAtIndexPath
. This works for me, and I didn't find it necessary to overridelayoutSubviews
in the cell subclass.I had a similar problem with a static UITableView. I change a label's text and it doesn't get updated on the screen unless I clicked on the cell or did anything to force update its views. My workaround was to call after updating the text:
tableView.reloadData()
P.S This doesn't make any sense; because this is a static table view, and I don't know why it worked, but it did!
So, I followed this tread and many others. This one lead me to what seems to be the correct answer. I hope this helps others, since this has driven me crazy since iOS 7 / 8 made some sort of changes.
My answer was to put the normal processing code in viewWillAppear and add this [self.tableview layoutSubviews] instead of [self.tableView reload data]. I think this has to do with Apple making things much more controllable in iOS 7 / 8. I struck upon that idea when reviewing some info on how cells were working.
Again, I hope this helps others resolve this annoying problem.
Confirming the problem using Xcode 6.3.2 (6D2105) OS X Yosemite 10.10.3 I made sure that the correct value was being assigned, still first time no show, second time show. cell.layoutSubviews() seemed logical to me since it appeared as if the view lacked a refresh and adding layoutSubviews() did the trick.
I have same problem with cell not updating correctly when using segue in storyboard. Tried
on the view and the tableview and it is NOT working.
Then I tried the advice from pixbug, and it worked. But one should NOT use [layoutSubviews] directly. So I tried the ones that is adviced by the documents on the cell instead of tableView or the view.
Tried
but this did NOT work.
Tried
this WORKED for me.
I put this before returning the cell.
I think that if you need to reloadData, that means that the table data isn't loaded when its created.
You'd just need to load your data in the viewdidload (or somewhere else BEFORE the table view gets its data ) where your tableview is, and then create the cells accordingly.
Usually, i just use an array of whatever object i'm using and then use
[array objectAtIndex:indexpath.row]
, which you probably know about.Also, you ante-last paragraph has an unfinished sentence that looks important.