I successfully implemented the self-resizing cells with autolayout. I added a UITextField to my content view that takes a string from the model, and the cell is now resizing correctly according to the length of the string.
The user is supposed to be able to edit this text field - how do I update the frame of the cell on user input (as the text field grows)?
I could resize the cells and the rest of the table view manually, but I figured there might be a better and simpler way to invalidate and refresh the frame of the cell that is being edited?
I want the frame changes to animate smoothly (e.g. as the textfield text requires a new line, this cell grows in height, and the cells below are pushed down accordingly).
If you just want to refresh a single cell you can do the following:
[self.tableView beginUpdates];
[self.tableView reloadRowsAtIndexPaths:#[[NSIndexPath indexPathForItem:0 inSection:0]] withRowAnimation:UITableViewRowAnimationNone];
[self.tableView endUpdates];
Obviously you should change the indexpath to the correct one for your cell.
If you do this in something like textViewDidBeginEditing after checking if the contentSize of the UITextView has changed you should get the effect you're after.
Related
I am using a datepicker in a table cell. I load the table cell at particular cellIndex. and gives its height to 0. So that on the button click I make it visible and hide accordingly.
The issue coming in this case is. When date picker is shown and i want to hide it. And click the button then picker height is reduced to instantly but table view animates to reduce its cell height to 0.
by user propactive it feels odd that picker compress first and tablecell reduces to 0 later. How should i make them animate so that the cell animation to reduce height will looks good.
I am using begin/end update to make this happen
The simplest would be to use the UITableView's builtin animations instead of animating the height yourself. This could be done like so:
[tableView beginUpdates];
[tableView deleteRowsAtIndexPaths:#[ indexPathOfYourCell ] withRowAnimation:UITableViewRowAnimationTop];
[tableView endUpdates];
See UITableViewRowAnimation for more animation options.
I'm making a UIViewController to manage a messaging screen. I'm doing this using a UITableView and some custom cells.
To make things simpler, each cell contains:
Its chat "bubble" (a UIView subclass)
Its chat text (a UILabel)
A timestamp header label (which might be hidden)
A bottom footer label (for "Sending...", "Delivered", etc.; also might be hidden)
Because of performance concerns, I am not using auto-sizing of cell heights, but caching cell heights into an NSMutableDictionary.
When the user sends or receives a new message, I want the following to occur:
The current last message cell is reloaded, hiding its bottom label, if needed.
The new last message cell is appended at the bottom of the UITableView.
The UITableView is scrolled so that the new last cell is visible.
I can get it to where the end state of the screen is as desired, but the animations in between are really kinda funky. I have tried a whole lot of different approaches to get the animations to behave. Basically, it seems like some major reloading is happening, even though the only cell that could possibly change its height is the last cell (prior to the insertion of the new cell). Plus, I'd like to have the last cell simply "appear" in place without animation. If it does, it should be off-screen, and then I should be able to animate it on-screen.
Here's my current "user sent a new message" method:
- (IBAction)sendButtonPressed {
//Creation of the new message, into 'message' variable
[self.messages addObject:message];
int thisIndex = (int)self.messages.count - 1;
NSIndexPath *this = [NSIndexPath indexPathForRow:thisIndex inSection:0];
int prevIndex = (int)self.messages.count - 2;
NSIndexPath *prev = [NSIndexPath indexPathForRow:prevIndex inSection:0];
[self removeCachedHeightForIndex:prevIndex];
[self.tableView beginUpdates];
[self.tableView reloadRowsAtIndexPaths:#[prev] withRowAnimation:UITableViewRowAnimationNone];
[self.tableView insertRowsAtIndexPaths:#[this] withRowAnimation:UITableViewRowAnimationTop];
[CATransaction setCompletionBlock:^{
[self scrollToBottomAnimated:YES];
}];
[self.tableView endUpdates];
}
This appears to reload the last several cells in the UITableView. Or, at least, every cell that is visible when this is called seems to be animated in some way. Only the cell at prev is actually changing in any way.
Longterm, I might pull out the header and footer labels into different cells, but is there a way to fix this animation glitch as-is?
I'm using a UISegmentedControl which changes the contents of a UITableViewCell. After the segment changes I need to reload the cell to update the height of it. I do this by calling:
[self.tableView reloadRowsAtIndexPaths:#[self.segmentIndexPath] withRowAnimation:UITableViewRowAnimationNone];
However, this makes the UITableView scroll to the top. What is the best way to do this without having the table scroll?
Try to use [self.tableView visibleCells] and then find this cell and change
I have a tableviewcell, that on tap, grows in size, height wise, by updating the frame.
The problem is, the cells below don't adjust, move down to make it visible underneath, and the select row events are still based on the old sizes, before tap. I am using Facebook POP - which is handling animation, so tableview.beginUpdates() is out of the question, maybe?
You cannot manually update the frame of a UITableViewCell by changing its frame or bounds. Instead, you need to change the value returned by -tableView:heightForRowAtIndexPath: for that indexPath and then perform:
[self.tableView beginUpdates];
[self.tableView endUpdates];
This will cause the tableView to recalculate the heights of all the rows.
First, you need to make sure that you return the new height in heightForRowAtIndexPath, then you need to make the tableview update the cell. If you don't care about animation just call [tableview reloadData]. If you want animation you need to call [tableview reloadRowAtIndexPath: indexpath_of_your_cell]
I have a custom UITableViewCell with objects in it (such as UILabel, UITextView, UITextField etc.). When a button gets selected, a cell gets added to the tableView.
When I run it on the simulator, and the cell gets added, all the visible cell's and subviews height get really compact. (I do have auto constraint applied.)
....
[[self myTableView] insertRowsAtIndexPaths:paths withRowAnimation:UITableViewRowAnimationTop];
If I do the following, the cells get back to normal:
NSArray* visibleCellIndex = self.myTableView.indexPathsForVisibleItems;
[self.myTableView reloadRowsAtIndexPaths:visibleCellIndex withRowAnimation:UITableViewRowAnimationFade];
[self.myTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:savedScrollPosition inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:YES];
The problem with reloading the visible cells, is: First, that's a workaround, not getting to the source of the problem. Second, it's not a fully functioning workaround, because the whole tableView scrolls all the way up for a second, then scroll back to position.
The reason why it was shrinking, is because, you have to implement the method of heightForRowAtIndexPath.
The only problem now, is that the tableView jumps up, then scrolls to position. Don't know why.
Does your target run only on iOS 8 and later? If yes, you can set self.tableView.rowHeight = UITableViewAutomaticDimension to enable Autolayout for your cells. Then, you also don't need to implement delegate tableView:heightForRowAtIndexPath:.
If you're already doing this, your problem probably lies in your custom cell. Maybe its constraints are not well defined? How do you initialize the cell's constraints?
Another idea is to trigger the layout pass manually in tableView:cellForRowAtIndexPath:. After the cell has been initialized and its text label values have been set, call:
[cell setNeedsLayout];
[cell layoutIfNeeded];