I have a table view with a number of cells. When I add a new cell (using a modal view controller) I'd like to show the user the newly added cell. To do this I want to scroll the table view to the new cell, select it and immediately deselect it.
Right now, I'm sending a deselectRowAtIndexPath to my table view after a timed interval:
- (IBAction)selectRow
{
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:7 inSection:0];
[self.tableView selectRowAtIndexPath:indexPath animated:YES scrollPosition:UITableViewScrollPositionTop];
[self performSelector:#selector(deselectRow:) withObject:indexPath afterDelay:1.0f];
}
- (void)deselectRow:(NSIndexPath *)indexPath
{
[self.tableView deselectRowAtIndexPath:indexPath animated:YES];
}
I'm wondering if there's a nicer way to do this. It works well, but I don't like relying on a static timer to perform an operation which could sometimes take a different amount of time (e.g. if the table was very long).
Edit: Note that selectRowAtIndexPath:animated:scrollPosition won't cause the UITableView delegate methods to get fired. Neither tableView:didSelectRowAtIndexPath: nor scrollViewDidEndDecelerating: will be called. From the docs:
Calling this method does not cause the delegate to receive a tableView:willSelectRowAtIndexPath: or tableView:didSelectRowAtIndexPath: message, nor will it send UITableViewSelectionDidChangeNotification notifications to observers.
UITableViewDelegate is an extension of UIScrollViewDelegate. You could implement one of the UIScrollViewDelegate methods and use that to determine when to deselect the row. scrollViewDidEndDecelerating: seems like a good place to start.
Also, I personally find the performSelector... methods limiting due to the 1 parameter restrictions. I prefer to use GCD. The code would look like this:
- (IBAction)selectRow
{
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:7 inSection:0];
[self.tableView selectRowAtIndexPath:indexPath animated:YES scrollPosition:UITableViewScrollPositionTop];
//deselect the row after a delay
double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
[self.tableView deselectRowAtIndexPath:indexPath animated:YES];
});
}
Related
I have 3 tableview which have 10 rows, after pull to scroll it adds next 10 rows, but the scroll goes to top, I want it from the same row, which was before.
- (void)insertRowAtBottom {
int64_t delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
[self moreClicked];
});
}
You can save the last index path of the table view in any variable when pull happens and then use the below code to scroll the table
NSIndexPath *lastIndexPath = [NSIndexPath indexPathForRow:(numberOfRows - 1) inSection:(numberOfSections - 1)];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:lastIndexPath inSection:0];
[self.tableview scrollToRowAtIndexPath:indexPath
atScrollPosition:UITableViewScrollPositionTop
animated:YES];
For Scroll positions you can have any value within the list.
UITableViewScrollPositionNone,
UITableViewScrollPositionTop,
UITableViewScrollPositionMiddle,
UITableViewScrollPositionBottom
There are a few ways to implement "paging" in tableView.
One approach is: Assuming your tableView is populated from an objects array -
When you scroll down and fetch the next 10 items - just append the newly added data to your datasource array, and then call [self.tableview reloadData];
this will keep you exactly where you were. no need for scrolling methods or animations.
So I am trying to delete rows in table view.
Here is my code:
- (IBAction)done:(UIStoryboardSegue *)segue
{
DetailGodsViewController *detailController = [segue sourceViewController];
NSIndexPath *path = [NSIndexPath indexPathForRow:detailController.row inSection:detailController.section];
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:path]
withRowAnimation:NO];
[self.listOfGoods deleteGood: detailController.row];
[[self tableView] reloadData];
[self dismissViewControllerAnimated:YES completion:NULL];
}
I have ControlViewTable in storyBoard, after I click on a row in ControlViewTable it jumps to Detail view And there is other info, also I store info about the row and section in this function:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"ShowGoodDetails"]) {
DetailGodsViewController *detailViewController = [segue destinationViewController];
detailViewController.row = [self.tableView indexPathForSelectedRow].row;
detailViewController.section = [self.tableView indexPathForSelectedRow].section;
detailViewController.good = [self.listOfGoods getGoodAtIndex:detailViewController.row ];
}
and there is also a button in detail view for delete, after I click on it, it jumps to the function:
- (IBAction)done:(UIStoryboardSegue *)segue.
But it always crashes in deleteRows. Could someone please help?
One problem might be that you're still responding to the button while you're trying to get rid of the cell containing the button. You need to let that action method end, and then call deleteRows. You should probably do the sort of thing I recommend here:
https://stackoverflow.com/a/13907375/341994
However, the biggest problem is probably that you must update the model data before deleting a row of the table.
Your code in the done: method is doing a few things out of order plus some extra things you don't need. It should be:
- (IBAction)done:(UIStoryboardSegue *)segue
{
DetailGodsViewController *detailController = [segue sourceViewController];
NSIndexPath *path = [NSIndexPath indexPathForRow:detailController.row inSection:detailController.section];
[self.listOfGoods deleteGood: detailController.row];
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:path]
withRowAnimation:NO];
[self dismissViewControllerAnimated:YES completion:NULL];
}
Basically, you need to update your data before you update the table. Also, don't call reloadData on the table after calling deleteRowsAtIndexPaths:. Do one or the other, not both.
If count of the Array that tableview is using is 1 then how to select the first row in the table i used the following code it is selecting but not navigating to next screen
NSIndexPath * ip =[NSIndexPath indexPathForRow:0 inSection:0];
[npTable selectRowAtIndexPath:ip animated:YES scrollPosition:UITableViewScrollPositionNone];
you have to use some delegate methods for uitabelview
you have to add UITableViewDataSource,UITableViewDelegate.
You have to add the delegate method of uitabelview i.e)
Add delegate method as below.
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//here you have to write the code for to navigate next screen.
sample *sampleobject=[[sample alloc]init];
[self.navigationController pushViewController:sampleobject animated:YES];
}
that's it enjoy now u can naviagte to another page..
This only highlights the table cell. You would need to call the code which would appear in your tableView:didSelectRowAtIndexPath method or alternatively you could call it yourself like:
NSIndexPath * ip =[NSIndexPath indexPathForRow:0 inSection:0];
[self tableView: npTable didSelectRowAtIndexPath: ip];
I have a view controller that manages a table view. My understanding is that a table cell will be deselected automatically if I push another viewcontroller and then pop back to the table view.
However, in the same class (that I use a few times), there is one instance of the class when the cell is deselected but not animated (it'll just turn blue and then back to normal without animating). Why did this happen? I have a few instances of this class but it only happens to one of them. What might be causing this?
From my experience cells are not automatically deselected if you push/pop a view controller (at least not when using a navigationcontroller), unless you add some code te deselect it !
It may also be automatically deselected if you are doing a [tableView reloadData] in viewWill/DidAppear (or in a process started in these methods).
Did you try to add something like that in viewDidAppear ?
NSIndexPath *indexPath = [tableView indexPathForSelectedRow];
if (indexPath != nil) {
[tableView deselectRowAtIndexPath:indexPath animated:YES]
}
NSIndexPath *indexPath = [tableView indexPathForSelectedRow];
if (indexPath != nil) {
[tableView deselectRowAtIndexPath:indexPath animated:YES]
}
this you have to write in didselectRowAtIndexPath method
You can reload the Tableview again.
In your viewWillAppear
[yourTableView reloadData];
Or if you dont want to disturb your Datasource try this
NSArray *array = [yourTableView visibleCells];
for(UITableViewCell *cell in array)
{
cell.selected = NO;
}
I have a UISplitViewController with a Table View for navigation. It's similar to the Mail app. When you click on a table view in portrait mode, the popup hides itself. When you click on the nav bar to get the popup back, the selected item no longer appears selected. How can make this item appear selected without re-selecting the item? (just like in the mail app)
In your viewDidLoad method, do you call
self.clearsSelectionOnViewWillAppear = NO; ?
This is how Xcode's SplitView template does it.
Do you have by any change a
[tableView deselectRowAtIndexPath:indexPath animated:YES];
in your didSelectRowAtIndexPath in the RootViewController ?
I've got a solution that works, but it's frustratingly hacky. I have to call selectRowAtIndexPath twice. It seems that cellForRowAtIndexPath is invalidating the selection made in viewWillAppear. It still needs to be called in viewDidAppear, however, so the view scrolls to the proper position before cellForRowAtIndexPath is called.
- (void)viewWillDisappear:(BOOL)animated
{
NSIndexPath *selected = [self.tableView indexPathForSelectedRow];
_selectedRow = selected.row;
}
- (void)viewDidAppear:(BOOL)animated
{
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:_selectedRow inSection:0];
[self.tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionMiddle];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//initialize cell code here...
if (indexPath.row == _selectedRow) {
[self.tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionMiddle];
}
}
For your table view controller, is -viewWillAppear: called before the pop-up is displayed? If so, you could write it as so:
- (void)viewWillAppear:(BOOL)animated
{
[self.tableView selectRowAtIndexPath:<indexPath>
animated:animated
scrollPosition:UITableViewScrollPositionMiddle];
[super viewWillAppear:animated];
}
Obviously, replace <indexPath> with the proper index path and set the scroll position how you want it. You may also want to pass NO instead of animated to make it appear like it was selectd before the view appeared.