selectRowAtIndexPath only works when allowsMultipleSelection is YES - iphone

I have a UITableViewController that is populated dynamically depending on a previous selection by the user. In some cases, the user should be able to select multiple rows in the table but in other cases he should not. I want to automatically select the first row in either case, but I have found that it only works when I have allowsMultipleSelection = YES.
The following code is called during -(void)viewDidLoad
switch(self.field)
{
case people:
self.options = (NSArray *)[data objectForKey:#"People"];
self.tableView.allowsMultipleSelection = YES;
enter code here break;
case place:
self.options = (NSArray *)[data objectForKey:#"Places"];
self.tableView.allowsMultipleSelection = NO;
break;
case reason:
self.options = (NSArray *)[data objectForKey:#"Reasons"];
self.tableView.allowsMultipleSelection = NO;
break;
}
[self.tableView reloadData];
NSIndexPath *zeroPath = [NSIndexPath indexPathForRow:0 inSection:0];
[self.tableView selectRowAtIndexPath:zeroPath animated:NO scrollPosition:UITableViewScrollPositionNone];
This works correctly for the "People" case but not for the others. I have tried setting allowMultipleSelection to YES and that solves the problem of the selection, but it is not acceptable in terms of the application logic.
Am I missing something about how these functions work? How can I programmatically select a row in a single selection table?

Fixed with the following from the template:
// Uncomment the following line to preserve selection between presentations.
self.clearsSelectionOnViewWillAppear = NO;
Still not sure exactly why it didn't work before.

for (NSIndexPath *indexPath in [self.tableView indexPathsForSelectedRows]) {
[self.tableView deselectRowAtIndexPath:indexPath animated:NO];
}
[self.tableView selectRowAtIndexPath:zeroPath animated:NO scrollPosition:UITableViewScrollPositionNone];

Related

Edit animation UITableViewStyle like addressbook

I need some help with UITableView. I'm looking for the best solution for creating edit table functionality. I have UITableViewController with data and two modes:
Edit mode: All fields (like first name, last name, phone, web page etc...)
View mode: Show only filed rows.
The difficult thing is to animate the rows when a user clicks the edit button.
I want the same animation we have in the address book app on iPhone.
Something like this in simple.
//original position and maybe hidden
someView.frame = CGRect(0,0,0,0);
someView.alpha = 0.0f;
[someView setHidden:YES];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.3];
//what you want it comes out finally, changed position and visible
[someView setHidden:NO];
someView.frame = CGRect(100.0f,100.0f,0,0);
someView.alpha = 1.0f;
[UIView commitAnimations];
Use
[tableView setEditing: YES animated: YES];
to make the UItableView in editing mode.Which give you show and hide the button when you swipe on the row.if your animation is something please let me know.
I have solution!
Help from this article
So you need add something like this (thanks Sandy)
- (void)setEditing:(BOOL)editing animated:(BOOL)animated{
[super setEditing:editing animated:animated];
NSArray *paths = [NSArray arrayWithObject:
[NSIndexPath indexPathForRow:1 inSection:0]];
if (editing) {
[[self tableView] insertRowsAtIndexPaths:paths
withRowAnimation:UITableViewRowAnimationTop];
}else {
[[self tableView] deleteRowsAtIndexPaths:paths
withRowAnimation:UITableViewRowAnimationTop];
}
}
After that
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
will be colled, and you can edit list of cells and their appearance.
in the case below, I have 2 sections, first section contains a series of settings, first row is a default setting, always there and can't be reordered, and second one contains just one row like 'Add...', editing is only for reordering and deleting so in edit mode I remove the first setting, and remove the 2nd section, and it animates smoothly if you club all your insert/delete within a beginUpdates/endUpdates on the tableview. So for you it would be just the opposite, adding more rows/sections when editing
In Normal mode I have :
Countries (<-- 1st section)
- World
- Argentina
- USA
(<-- 2nd section)
- Add Countries...
In Edit mode I have :
Countries (<-- 1st section)
- Argentina = (can be removed/reordered)
- USA = (can be removed/reordered)
Code looks like:
- (void)setEditing:(BOOL)editing animated:(BOOL)animated
{
[super setEditing:editing animated:animated];
NSArray *paths = [NSArray arrayWithObjects:
[NSIndexPath indexPathForRow:0 inSection:0],
nil];
[self.tableView beginUpdates]; // Club all updates together
if (editing)
{
if( [[CCPollSettings countryCodes] count] < 2) // No country setting
// Remove complete section
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationFade];
else // Remove first default row
[self.tableView deleteRowsAtIndexPaths:paths withRowAnimation:UITableViewRowAnimationFade];
// Remove 'Add...' Section
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:1] withRowAnimation:UITableViewRowAnimationFade];
// .... Do more stuff after
} else {
if( [[CCPollSettings countryCodes] count] < 2) // No country setting yet
[self.tableView insertSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationFade];
else // add back default row
[self.tableView insertRowsAtIndexPaths:paths withRowAnimation:UITableViewRowAnimationFade];
// Add back 'Add...' Section
[self.tableView insertSections:[NSIndexSet indexSetWithIndex:1] withRowAnimation:UITableViewRowAnimationFade];
}
[self.tableView endUpdates]; // Club all updates together
}

UITableView reload section

I want to reload only one section not the full table. Is there any method in UITableView.
[tableView reloadData] is used to load full table.
I want to know how to load only one section, as I have large number of rows in the table.
The reloadSections method bugs me -- as I have to construct a few objects. This is great if you need the flexibility, but sometimes I also just want the simplicity too. It goes like this:
NSRange range = NSMakeRange(0, 1);
NSIndexSet *section = [NSIndexSet indexSetWithIndexesInRange:range];
[self.tableView reloadSections:section withRowAnimation:UITableViewRowAnimationNone];
This will reload the first section. I prefer to have a category on UITableView and just call this method:
[self.tableView reloadSectionDU:0 withRowAnimation:UITableViewRowAnimationNone];
My category method looks like this:
#implementation UITableView (DUExtensions)
- (void) reloadSectionDU:(NSInteger)section withRowAnimation:(UITableViewRowAnimation)rowAnimation {
NSRange range = NSMakeRange(section, 1);
NSIndexSet *sectionToReload = [NSIndexSet indexSetWithIndexesInRange:range];
[self reloadSections:sectionToReload withRowAnimation:rowAnimation];
}
Yes, there is:
- (void)reloadSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation
But you can reload only sections which contain same number of rows (or you have to manually add or remove them). Otherwise you will get:
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 2. The number of rows contained in an existing section after the update (1) must be equal to the number of rows contained in that section before the update (0), plus or minus the number of rows inserted or deleted from that section (0 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).'
Which is not required when you use [tableView reloadData].
When you need to reload a section and you have changed number of rows inside it, you could use something like this:
NSIndexSet *indexSet = [NSIndexSet indexSetWithIndex:section];
[self beginUpdates];
[self deleteSections:indexSet withRowAnimation:rowAnimation];
[self insertSections:indexSet withRowAnimation:rowAnimation];
[self endUpdates];
If you put it in a category (like bandejapaisa shows) it could look like this:
- (void)reloadSection:(NSInteger)section withRowAnimation:(UITableViewRowAnimation)rowAnimation {
NSIndexSet *indexSet = [NSIndexSet indexSetWithIndex:section];
[self beginUpdates];
[self deleteSections:indexSet withRowAnimation:rowAnimation];
[self insertSections:indexSet withRowAnimation:rowAnimation];
[self endUpdates];
}
For Swift 3, 4 and 5
let sectionToReload = 1
let indexSet: IndexSet = [sectionToReload]
self.tableView.reloadSections(indexSet, with: .automatic)
that the correct way:
[self.tableView beginUpdates];
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationNone];
[self.tableView endUpdates];
Based on the accepted answer here, I made a function that will reload all sections in the table using an animation. This could probably be optimized by reloading only visible sections.
[self.tableView reloadData];
NSRange range = NSMakeRange(0, [self numberOfSectionsInTableView:self.tableView]);
NSIndexSet *sections = [NSIndexSet indexSetWithIndexesInRange:range];
[self.tableView reloadSections:sections withRowAnimation:UITableViewRowAnimationFade];
In my case, I had to force a reloadData before the section animation, because the underlying data for the table had changed. It animates properly however.
You need this... For Reload Row
- (void)reloadRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation
or For Reload section
- (void)reloadSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation
Here is the method, you can pass section details in different ways
[self.tableView reloadSections:[[NSIndexSet alloc] initWithIndex:1] withRowAnimation:NO];
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:1] withRowAnimation:UITableViewRowAnimationNone];
Reloading particular sections improves performance for the table view as well some time it also avoid some issues like floating/moving custom headers-footers in your view. SO try to use reloadSection than relaodData whenever possible
Try to use
[self.tableView beginUpdates];
[self.tableView endUpdates];
Hope this will solve your issue.
But you can reload only sections which contain same number of rows (or you have to manually add or remove them). Otherwise you will get an NSInternalInconsistencyException.
Steps:
calculate which rows to remove and/or insert
generate an IndexPath array from these
call related tableView methods
now you can safely call reloadSections :) Reload section will call update for the rest of the indexes.
Or you can use a library like : https://github.com/onmyway133/DeepDiff
Swift pseodo code:
tableView.deleteRows(at: valueIndexesToRemove, with: .automatic)
tableView.insertRows(at: valueIndexesToInsert, with: .automatic)
tableView.reloadSections(IndexSet([section]), with: .automatic)
If you have custom section view you can add a weak reference to it in your view controller and update it whenever you want. Here is my code for reference:
#property (weak, nonatomic) UILabel *tableHeaderLabel;
....
-(UIView *) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
UITableViewHeaderFooterView *myHeader = [[UITableViewHeaderFooterView alloc] init];
UILabel *titleLabel = [[UILabel alloc] init];
[titleLabel setFrame:CGRectMake(20, 0, 280, 20)];
[titleLabel setTextAlignment:NSTextAlignmentRight];
[titleLabel setBackgroundColor:[UIColor clearColor]];
[titleLabel setFont:[UIFont systemFontOfSize:12]];
[myHeader addSubview:titleLabel];
self.tableHeaderLabel = titleLabel; //save reference so we can update the header later
return myHeader;
}
Then later on you can update your section like this:
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
self.tableHeaderLabel.text = [NSString stringWithFormat:#"Showing row: %ld", indexPath.row];
}

Set first cell to highlighted on view's load

I have a UISplitViewController. When the app launches initially, the detail view is showing the detail data for the first row. However, the cell in the table is not highlighted, since it hasn't been selected yet. How can I set it to selected by default when the app loads initially?
I added this to cellForRowAtIndexPath but its not highlighting. It highlights fine when I actually select a cell.
if (indexPath.row == 0)
{
cell.selected = YES;
}
-(void)selectFirstRow {
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
// optional:
// [self tableView:myTable willSelectRowAtIndexPath:indexPath];
[myTable selectRowAtIndexPath:indexPath animated:YES scrollPosition:UITableViewScrollPositionTop];
// optional:
// [self tableView:myTable didSelectRowAtIndexPath:indexPath];
}
Then call [self selectFirstRow]; wherever you need to.

how to delete a row in a section and hiding the section?

I am having an issue where when i have two sections let say section x and section. Section x has one row and also section y. If i delete a row in section y which is the second one, it will delete the row in section x and keeping the row in section y also it leave a space when i hide the section if their is a way to hide the section which wont make a mess please tell me a way here are some picture that might let u understand my question
and here is the code i use to delete a row
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
int path;
path = indexPath.row;
[data removeObjectAtIndex:path];
if([data count] == 0)
{
UIBarButtonItem *leftbutton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemEdit target:self action:#selector(editTable)];
self.navigationItem.rightBarButtonItem = leftbutton;
[leftbutton release];
[self.navigationItem.rightBarButtonItem setEnabled:FALSE];
[mainTableView setHidden:TRUE];
}
else
{
[self.navigationItem.rightBarButtonItem setEnabled:TRUE];
[mainTableView setHidden:FALSE];
}
[self saveData];
[mainTableView reloadData];
}
To remove a section when you have deleted all rows belonging to it, call - (void)deleteSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation & return one less from - (NSInteger)numberOfSections.
You haven't added any code that shows how you are deleting a row from the table (removing it from data isn't sufficient). Try something like-
[self.tableView beginUpdates];
[data removeObjectAtIndex:path];
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone];
[self.tableView endUpdates];
Well at the beginning i wasn't able to solve the issue but with the help of #Akshay my first problem was while deleting it always delete the section on top the section i was deleting to solve the issue i just had to update the number of rows in a section using
[mainTableView reloadData]; before the return expression

Programmatically highlight first row in tableview after first load

Im trying to highlight the first row in my table upon first loading the data and just cannot get it to work!
I have tried lots of ways with no joy, the latest attempt being this:
NSUInteger indexArr[] = {0,1};
NSIndexPath *n = [NSIndexPath indexPathWithIndexes:indexArr length:2];
[self.tableView scrollToRowAtIndexPath:n atScrollPosition:UITableViewScrollPositionTop animated:NO];
try
[self.tableView selectRowAtIndexPath:n animated:YES scrollPosition:UITableViewScrollPositionTop];
you should probably do this after your view has appeared.