How to reload Data of TableView when Editing ends with animation - iphone

I'm using a TableView to show, edit and write Data to a file...when the editing modes end I write them to the file and afterwards I want to clear the inputFields of the tableCells.
I'm doing this with:
- (void) setEditing:(BOOL)editing animated:(BOOL)animated {
[super setEditing:editing animated:animated];
if (editing == NO) {
//Write to file
//Clear Data
[self.tableView reloadData];
}
}
but when i reload the Data the animation isn't shown.
What way can i reload the Data and still get an animation?

Why not just clear the input fields in the existing cells instead of calling reloadData? Iterate through all of the UITableViewCells in self.visibleCells and clear the input field in each of them in turn - that should leave the animation uninterrupted.

Related

Differentiate Between UITableView Editing States?

I have been looking at trying to differentiate between editing states in my UITableView.
I need to call a method only when in editing mode after tapping the edit button, so when you get your cell slide in and you see the little circular delete icons but NOT when the user swipes to delete.
Is there anyway I can differentiate between the two?
Thanks.
EDIT:
Solution thanks to Rodrigo
Both each cell and the entire tableview has an 'editing' BOOL value, so I loop through all the cells and if more than one of them is editing then we know the whole table is (the user tapped the edit button), however if only one is editing then we know that the user has swiped a cell, editing that individual one, this lets me deal with each editing state individually!
- (void)setEditing:(BOOL)editing animated:(BOOL)animated
{
[super setEditing:editing animated:animated];
int i = 0;
//When editing loop through cells and hide status image so it doesn't block delete controls. Fade back in when done editing.
for (customGuestCell *cell in self.tableView.visibleCells)
{
if (cell.isEditing) {
i += 1;
}
}
if (i > 1)
{
for (customGuestCell *cell in self.tableView.visibleCells)
{
if (editing)
{
// loop through the visible cells and animate their imageViews
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.4];
cell.statusImg.alpha = 0;
[UIView commitAnimations];
}
}
}
else if (!editing)
{
for (customGuestCell *cell in self.tableView.visibleCells)
{
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.4];
cell.statusImg.alpha = 1.0;
[UIView commitAnimations];
}
}
}
Even if this post is quite old, the following might be helpful to others:
If you implement the following delegate messages:
- (void)tableView:(UITableView *)tableView willBeginEditingRowAtIndexPath:(NSIndexPath *)indexPath;
and
- (void)tableView:(UITableView *)tableView didEndEditingRowAtIndexPath:(NSIndexPath *)indexPath;
These methods will be called when editing a single line. -[UIViewController setEditing:animated:] will then only get called when the user hits the edit button.
There are one strategy, I do not test now, but maybe work.
You can set the UITableView to be in editing mode and test with isEditing function. But the cell have the same isEditing. So you can check if only one cell is in editing state or all the UITableView.
Check if when you set one cell to be in editing state, the UITableView change to editing state at all.
The solution I chose was to override the action for the edit button to a custom method, say editBtnTapped. In this method I set a variable editButtonPressed, and then, because we overrode the the edit button's action, manually call setEditing:animated:.
In viewDidLoad:
[self.navigationItem.rightBarButtonItem setAction:#selector(editBtnPressed)];
And then the new action method:
- (IBAction) editBtnPressed
{
if ([self isEditing])
{
self.editButtonPressed = NO;
[self setEditing:NO animated:YES];
}
else
{
self.editButtonPressed = YES;
[self setEditing:YES animated:YES];
}
}
Now in setEditing:animated: I check the editButtonPressed flag to determine if I'm in there because of an Edit button press or a simple user swipe. If I'm there due to the Edit button, I add the cell; otherwise I don't.
Keep in mind you may need the flag elsewhere, (e.g. numberOfRowsInSection).
Hope this alternative helps.
Regards,
--John
The only reliable way I have found to do this is to maintain a private flag inEditMode and toggle this flag in setEditing:animated. Then use inEditMode rather than isEditing to check if the table is in edit mode or not.

Three20 Empty Table View when Model is Not Finish Loading

The situation here is, I have an application with a tab bar, and each tab has a TTTableViewController with Datasource and TTURLRequest Models
When I do this series of actions, i get this no data table:
(1) While my fist view is loading, and the items is not yet displayed (Three20 Loading...)
(2) then I switch to another tab
(3) Then go back to that first view, I get an empty table. but when
I tried to breakpoint and look into the visible cells, the model, the datasource, they have values, but how come it displayed an empty table.
So here's a quick fix for my problem, i know this is not the best way.So what I did was to set a private boolean if it needs to invalidate the model, when user moves to another view and while the model is not yet loaded, i set the flag _isNeedtToInvalidateModel=YES
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
if(_isNeedToInvalidateModel) {
[self invalidateModel];
_isNeedToInvalidateModel = NO;
}
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
if(![self.model isLoaded]) {
_isNeedToInvalidateModel = YES;
}
}
Somehow it does not show the empty table view anymore

reloading tableview and touch gestures

I have a tableview which is being reloaded as new content is added, using [tableview reloadData];
Trouble is I have a UILongPressGestureRecognizer on the TableCells in the Table and because the cells / table are being reloaded quite often the LongPress doesnt always have time to work as, I'm guessing it's internal timers are being reset when the cell/table is being reloaded.
Have you tried looking at the state of your UILongPressGestureRecognizers before [tableView reloadData] is called? For example:
// Returns |YES| if a gesture recognizer began detecting a long tap gesture
- (BOOL)longTapPossible {
BOOL possible = NO;
UIGestureRecognizer *gestureRecognizer = nil;
NSArray *visibleIndexPaths = [tableView indexPathsForVisibleRows];
for (NSIndexPath *indexPath in visibleIndexPaths) {
// I suppose you have only one UILongPressGestureRecognizer per cell
gestureRecognizer = [[tableView cellForRowAtIndexPath:indexPath] gestureRecognizers]
lastObject];
possible = (gestureRecognizer.state == UIGestureRecognizerStateBegan ||
gestureRecognizer.state == UIGestureRecognizerStateChanged);
if (possible) {
break;
}
}
return possible;
}
// ... later, where you reload the tableView:
if ([self longTapPossible] == NO) {
[tableView reloadData];
}
Let me know if it works!
Don't use reloadData if you want existing cells to remain. Instead, when you get new data, use the methods for Inserting and Deleting Cells to inform the table view exactly which cells have changed. The general procedure is:
You get new data.
Call beginUpdates
Call deleteRowsAtIndexPaths:withRowAnimation: to remove cells for any old items that have been deleted in the new data.
Call insertRowsAtIndexPaths:withRowAnimation: to add new cells for any items that have been added in the new data.
If you need to selectively replace a particular cell for some reason (and can't just update the existing cell's subviews with the new data), use reloadRowsAtIndexPaths:withRowAnimation:.
Call commitUpdates. At this point, your UITableViewDataSource methods must reflect the new data (e.g. tableView:numberOfRowsInSection: should reflect the changed count, and tableView:cellForRowAtIndexPath: should use the new items).
The table view will now call your data source methods as needed to update the display. Existing rows will not be changed.
Set a BOOL like aCellIsSelected to YES when you touch the cell
and just reload tableview if aCellIsSelected is NO

Ask for reloding the data and image in tableview

I use the custom table cell and in this i put 3 or more label and and one image view when I am use
[TableView reloadData];
at that time only data that in the label is change image is not change so plz give me advice for reloading image also
- (IBAction)reloadTableViewNext:(id)sender {
i=i+1;
AppDeleget.Page=[NSString stringWithFormat:#"%d",i];
[self viewWillAppear:YES];
[TableView reloadData];
}
Check if you are changing the image according to the reload in the cellForRowAtIndexPath.
Don't call
[self viewWillAppear:YES];
directly. If you like to redraw the whole view you can do the following in a view controller:
[self.view setNeedsDisplay];
The
[TableView reloadData];
should be fine to reload.
Please post the cellForRowAtIndexPath method. It's place where you (should) set the image.
Side Note
Reconsider using caps at the beginning for variable/field names, like TableView. It's a common practice in OO langugaes to use capital letters for class names.

UISearchDisplayContoller – can't prevent table reload on typing in search bar

I'm trying to set up a search display controller to handle async results from a web service. I've got the basic bits in place but have run into a really strange issue that I can't figure out.
Seems like to rig up the search display controller for async you really just need to do two things:
return NO for
searchDisplayController:shouldReloadTableForSearchString,
and
handle searchBarSearchButtonClicked
and fire off the table reload
myself.
I'm doing both of these but what I'm seeing is that the search display controller is reloading the table on the first character typed into the search bar even though I'm returning NO as per #1. It doesn't reload on subsequent characters entered.
So, my question is: how do I keep the search display controller from trying to reload the table while the user is typing? (specifically on that first character entered)
I've seen this issue mentioned as part of a couple of other questions but I have not seen a direct answer to the problem. I'd like to understand what's going on or what I'm doing wrong before I resort to a bunch of UI mangling to work around it.
Here's a quick distillation of my code to show the issue. When I run this and type "abcde" into the search bar, after I type "a" the results display as "a #0", "a #2", etc. They don't update again until I hit the search button then you see "abcde #0", "abcde #1", etc. Desired result is, of course, nothing happens until I hit the search button.
#pragma mark -
#pragma mark UISearchDisplayController Delegate Methods
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
return NO;
}
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchScope:(NSInteger)searchOption {
return NO;
}
#pragma mark -
#pragma mark UISearchBarDelegate Methods
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
[self.searchDisplayController.searchResultsTableView reloadData];
}
#pragma mark -
#pragma mark Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 20;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
cell.textLabel.text = [self.searchDisplayController.searchBar.text stringByAppendingFormat:#" #%d", indexPath.row];
return cell;
}
Thanks! (btw, this is my first question asked here—please let me know if I miss any points of etiquette :)
This is just the way UISearchDisplayController (SDC) works. When the user enters the first character into the searchBar the searchTable is loaded and displayed for the first time causing it to load. The methods "...shouldReloadTableForSearchString" and "...shouldReloadTableForSearchScope" allow you to control whether the searchTable reloads automatically on subsequent chars or a scope change.
I've done both of the following to provide a good user experience on the first character. Slight disclaimer: I do have implementations of both of these that work but this is simply a framework for implementation from my memory. I may have missed a detail but this should get you pretty close.
Option 1: Present a "loading" cell in the searchTable when the first char is typed.
This option allows the SDC to display the searchResultsTableView when the user types the first char, display status as to the current search/filter operation
in the SDC delegate class definition
add the iVar BOOL isLoading
add the iVar UITableView *searchTableView
in searchDisplayController:didLoadSearchResultsTableView
set searchTableView = tableView
in shouldReloadTableForSearchString/Scope
set isLoading = YES
call your method to load data in the background
return NO
when your background filter is complete:
set isLoading = NO
[searchTableView reloadData]
in the various tableView delegate methods respond how you like to show status if there are current search results or results are loading in the background. What I did is:
if there are current search results, show results (even if loading/filtering in the background)
if there are no search results and isLoading == NO return 1 row and show 'No matches' in a cell
if there are no search results and isLoading == YES return 1 row and and show search activity in a cell (I typically use UIActivityIndicatorView)
Option 2: Hide the searchTableView and display an overlay view in it's place until search results are loaded
This option hides the searchTableView when it is first loaded and only redisplays it if when the search/filter is complete. I defined this as an add on to option 1 as they can be done together though to optimize things you may not care about showing search activity in the searchResultsTableView if you are hiding the table and showing the overlay.
in the SDC delegate class definition
same as Option 1
add the iVar UIView *searchTableOverlayView
in searchDisplayController:didLoadSearchResultsTableView
same as Option 1
create a UIView to use as an overlay in place of searchTableView containing whatever UI is appropriate for your app and set it to searchTableOverlayView
in searchDisplayController:didUnloadSearchResultsTableView
release searchTableOverlayView
in 'searchDisplayController:didShowSearchResultsTableView(may be able to do this insearchDisplayController:willShowSearchResultsTableView`
if there are search results to display or isLoading == NO
seachTableOverlayView.hidden == YES
else (if isLoading == YES)
searchTableOverlayView.frame == searchResultsTableView.frame
add seachTableOverlayView as a subview of searchTableVIew.superview
searchTableView.hidden = YES
when your background filter is complete
same as option 1
if there are searchResults to display
searchTableCoverView.hidden = YES
searchResultsTableView.hidden = NO
else
searchResultsTableView.hidden = YES
searchTableCoverView.hidden = NO
in the various tableView delegate methods respond how you like to show status if there are current search results or results are loading in the background. What I did is:
same as option 1
Unfortunately I believe this is just how the UISearchDisplayController functions. You should file a bug report to Apple if you want to request different options for functionality.
The alternative would be to write your own UISearchBar and UITableView combination similar to how UISearchDisplayController works, then you'll get better control.
Hope this helps!
When I faced the same issue I tried to put an overlay view on search result view. That didn't help me. Looks like Apple change the behavior and I saw cell separators shone through my view. Finally I came up with a good approach.
At first my async search class had it's own overlay, progress and other views. UISearchDisplayController was used only for start, end delegate methods calls and sticking to default search flow.
To show view I used any subview I can put a search views on (as an init call):
newView.frame = frame;
[view addSubview:newView];
and then use the subview when changing my search progress views:
if (view == currentView)
return;
view.frame = currentView.frame;
view.alpha = [self getAlphaValueForView:view];
UIView * superView = [currentView superview];
[currentView removeFromSuperview];
currentView = view;
[superView addSubview:currentView];
The problem with empty search result table view blinking appears when I start to use my search content controller in default navigation routine (navigation controller).
So to solve the problem I start using for navigation not a content controller (in this case the default search display controller activating) but an empty controller. And I used empty controllers view as a subview for search views.
So in total: DO NOT use UISearchDisplayController's content view controller in navigation. Use stub view controller. And then use it's view to put your views as subviews.
Worked great for me.
Hide self.searchDisplayController.searchResultsTableView until user presse search button
- (void)searchDisplayController:(UISearchDisplayController *)controller didLoadSearchResultsTableView:(UITableView *)tableView;
{
tableView.hidden = YES;
}
After user press the search key, and the search results get ready, make the search result table visible
self.searchDisplayController.searchResultsTableView.hidden = NO;
[self.searchDisplayController reloadData]
This workaround works for me.
Maybe you need to implement UISearchDisplayController and then this function:
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText