I have a UITableView with complex content. The user can edit (rearrange and delete) the cells when tapping the Edit button the standard way. But I want the cells to look different in "edit" mode.
Question:
How to change the UITableView Layout in edit mode, including changing row height?
So far, this is what I have:
The Edit button sends a WillTransitionToState/DidTransitionToState message to each uitableviewcell (UITVC). I have subclassed UITVC and react to these inside each cell, hiding and removing and reshuffling as needed. But, changing the row height is beyond the scope of one cell.
There does not seem to be a message sent to UITableView when user taps edit. There is a - tableView:commitEditingStyle:forRowAtIndexPath: sent to data source after editing a particular row.
Inside heightForRowAtIndexPath, I can query the current mode using the tableView.editing property, and report height as appropriate. And I can trigger re-flowing the table, including recomputing the heights, by invoking [tableView reloadData]. But, when do I call it?
I could send messages from the cells from within WillTransitionToState back to the "owning" table view, and call reloadData when I get them. But this sounds fragile and there must be a better way.
Rhythmic is right. Using reloadData kills the nice editing animation.
This problem is addressed in this post:
Can you animate a height change on a UITableViewCell when selected?
Instead of using reloadData, do the following after calling setEditing:animated.
[tableview setEditing:editing animated:YES];
[tableview beginUpdates];
[tableview endUpdates];
If you wish for your table cells to change their format in response to whether or not the table is in editing mode, you could override -setEditing:animated: in your UITableViewController and trigger a reload (via -reloadData) of the table view on a change of editing state.
Within your UITableViewController's -tableView:cellForRowAtIndexPath: method, you could check for whether or not the table was in the editing state by querying the editing property on the table view, and then return a different cell type depending on which state the table is in.
Related
I've got a UITextView inside a UITableViewCell subclass. I have no problem getting the new height of the Text view and cell. The problem I have is telling the UITableView to update.
I have implemented heightForRowAtIndexPath: to return the live height of the cell as the TextView expands.
But somewhere `[tableView beginUpdates]; [tableView endUpdates]; must be called.
How? Should I add a delegate property to the UITableViewCell which is set to the UITableViewController subclass? And then send a delegate message when the cell expands height and the Tableview needs to update? It seems a little weird to have a delegate between the UITableViewCell and Controller?
I tried using NSNotificationCenter, but I have more than one editable cell, and more than tableview of this nature. So there is no way to register only for notifications for the cells without copying and pasting the same line over again, which isn't nice (as the cells are created in IB, and are not in an array or set), and having multiple tableviews means an exception occurs on the other table view as it is told to update but nothing changes.
I've seen lots of questions and answers on this topic, but when it comes to updating the tableview they all just say "now update the tableview" and not how to. So how do I telly he tableview to update, from one of it's cells?
I would think that this behavior would be best implemented in the UITableViewController instead of the view itself (the UITableViewCell).
Your controller is responsible for setting cell height, and typically will be the delegate for your UITextView's, so let it handle all of this.
In your textViewDidChange method, figure out what the new height of your cell should be, update your data structure to reflect that, and call reloadRowsAtIndexPaths:withRowAnimation: to have it actually change.
Edit:
So since you didn't like my first suggestion, another way to do this would be to add a recommendedRowHeight property to your custom UITableViewCell.
Then, you can either observe this property from your UITableViewController or implement a delegate protocol with a method along the lines of:
- (void)recommendedRowHeightDidChange
// or
- (void)recommendedRowHeightDidChangeTo:(CGFloat)newHeight
Then, when your height changes, update your recommendedRowHeight property and call your delegate's method if you go that route.
Either way, once your controller figures out that the recommended row height of a cell has changed, it can do what it is supposed to do. Update your data structures reflecting the current row heights and then call reloadRowsAtIndexPaths:withRowAnimation:.
You can add your tableview controller object as a weak reference to your tableview cell class. And in tableview controller you can have a method which will be called from tableview cell class.
I have a UITableView with some cells in it that have people's names. When the user clicks on a cell, the Navigation Controller pushes a new view onto the stack that shows detailed info for that person. When the user is done and clicks the button to return to the previous view, the tableview is again shown. The problem is that I want to edit the cell text (or just mark the cell in some way) to show that the user has clicked on that cell. In my cellForRowAtIndexPath: method I have set up code that should change the text of the cell after a user clicks on that cell. I set up break points and it IS entering cellForRowAtIndexPath: when the detail view is popped and the tableview is again shown. It's entering the segment of code in cellForRowAtIndexPath: that should change the text, but when it comes up on screen, the text has not been changed. Does anyone have any ideas as to what is going on? Thanks.
EDIT: I figured it out. I just needed to call [tableView reloadData]; instead of calling the cellForRowAtIndexPath method. Not sure why that works differently, but it fixed it.
I guess I'll help you out. You don't need to credit me with the answer though.
cellForRowAtIndexPath:
that method is called within the framework when a cell is being refreshed from the queue or when it needs to be created. You should not call this method.
[tableView reloadData];
that method is basically a refresh on all of the visible cells show in the UITableView. This is the method you should call if you change information in your data source or you need to (force) update the appearance of your cells.
It's Good You Have Reload Table And Changed The Text But If YouJustIndicate NAd Don't Want To Change The Text The nYou Can Use elow Given Text ....
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
It Will Check Mark Particuler Cell Which You Click/Visited......
Hope You Like This Solution.....
I've got a UITableView that has 20 sections. At the top I have a UISearchBar, and I want to filter the sections live as the user types.
Unfortunately, if the UISearchBar is active and if I return NO from searchBarShouldEndEditing: then my [tableView reloadData] call is ignored. If I return YES from searchBarShouldEndEditing: then the reloadData call works fine but I lose firstResponder after each character typed.
How can I force the UITableView to do live updates and filtering without having to resignFirstResponder on the UISearchBar between each character typed?
I faced the same problem and ended up with a quite elegant solution :
You place your search bar in a specific section of your table (let's say index 0). You place your table data in another section (let's say index 1).
When the text of your search bar changes, you can update your model and then simply call :
NSIndexSet *indexSet = [NSIndexSet indexSetWithIndex:1];
[self.tableView reloadSections:indexSet withRowAnimation:UITableViewRowAnimationAutomatic];
This way, your keyboard will still be active, your search bar will still be the first responder, and you will benefit from nice built-in table animations !
You could save yourself a lot of work by using the UISearchDisplayController and just feeding it the same datasource. It manages the search bar and its own table view for displaying filtered results.
I had similar problem. It turned out that it had to do with animations I used when table was reloading data. When I removed reloadSections:withRowAnimation, and simply called:
[self.tableView reloadData];
instead of calling fancier methods with animations for refreshing the table data, the search bar did not resign first responder on any key entered anymore.
Hope this helps...
This is driving me nuts.
I have a TableView with custom cells. My cell contains a editble textview. Is it possible to change rowheight on cell and textview dynamicly (when I editing the textView) ?
best regards
You can't change the height of a tableview cell without reloading the table. This means that every time a new line is needed in the textview, the tableview needs to reload.
While this can be done (with much manual tweaking,) I don't think the results will make for a good interface. Instead, you should have the cell open a detail view and let the user type there. This is how all the Apple apps handle the same problem and it is the solution most users will expect.
It will also save you a heck of a lot time and frustration.
The row height is calculated from either the delegate or the table view's property. I think the height is determined when the cell comes into view.
One possible avenue is to use - (void)reloadRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation.
Is the cell with with the text view unique in the table? You may run into problems if the user is in the middle of editing and the cell needs to be re-layed out and the text view is not unique.
yup!
try resizing your cell and calling
[tableView beginUpdates];
[tableView endUpdates];
every time you need to resize your cell.
that will call heightForRowAtIndexPath: and resize all your cells accordingly
so you want to return the proper height there..
hope that helps:)
currently I'm struggling with this problem:
I got a UITableViewController that displays a tableView with different custom cells.
One custom cell displays a number (by a label). If you click on this cell, the navigationController moves to a UIPicker where the user can select the number to be displayes.
If the user moves back, the cell should display the updated value.
Problem:
I managed to reload the cells by calling
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self.tableView reloadData];
}
in the UITableViewController.
This works only, if I don't use dequeueReusableCellWithIdentifier for the cell (tables won't show updates otherwise).
But in this case, memory usage grows and grows...
In addition, the program crashes after about 15 movements to pickerView and back - I think because the cell that should be reloaded is already released.
How can I update a reusable custom cell every time the view appears ?
What is the best solution ?
I think retaining cells should not be used ?
A general approach is to avoid reloading the whole table if only one cell is changed.
In such case, just get the reference to the UITableViewCell you want to "refresh" and invoke a [self setNeedsDisplay] from the main thread on it to trigger its refresh (will call the drawRect on it to trigger its drawing).
Have you set the appropriate id in the NIB? It has to be the same as you use when calling dequeueReusableCellWithIdentifier:
See step 3 here