UITableViewCell check/uncheck within one section only - uitableview

I'm trying to setup my table so that the user can select one item per section.
For example:
- Section 0
- Row 0 √
- Row 1
- Section 1
- Row 0
- Row 1 √
- Row 2
So in the above example if the user selects section 0, row 1 then row 0 in the same section should be unchecked and the selected row gets a checkmark.
Same goes for section 1 where any selected row should get a checkmark and then I want to remove the checkmark from the previously selected row in the same section.
- Section 0
- Row 0
- Row 1 √
- Section 1
- Row 0
- Row 1
- Row 2 √
Please keep in mind that I won't have a predefined number of sections or rows, so the code should work for this scenario. Here's what I currently have, hopefully that might get me started on the right path.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[self.tableView deselectRowAtIndexPath:indexPath animated:YES];
MyObject *myObject = [self.fetchedResultsController objectAtIndexPath:indexPath];
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
if ([myObject.optionSelected boolValue] == NO) {
[myObject setOptionSelected:[NSNumber numberWithBool:YES]];
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
} else {
[myObject setOptionSelected:[NSNumber numberWithBool:NO]];
[cell setAccessoryType:UITableViewCellAccessoryNone];
}
if ([tableView numberOfRowsInSection:indexPath.section] > 1) {
NSMutableArray *cells = [[NSMutableArray alloc] init];
for (NSInteger i = 0; i < [tableView numberOfRowsInSection:indexPath.section]; ++i) {
[cells addObject:[tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:indexPath.section]]];
}
for (UITableViewCell *deselectCell in cells) {
if ([self.tableView indexPathForCell:deselectCell] != indexPath && deselectCell != cell) {
MyObject *tempObject = [self.fetchedResultsController objectAtIndexPath:[self.tableView indexPathForCell:deselectCell]];
[tempObject setOptionSelected:[NSNumber numberWithBool:NO]];
[cell setAccessoryType:UITableViewCellAccessoryNone];
}
}
}
}
As you can see I am also setting the object's selected state, I'd like this to remain intact :)
Thanks for any feedback and help in advance!

Your tableview should declare a mutable array to hold the currently selected paths:
NSMutableArray *selectedCellPaths = [[NSMutableArray alloc] init];
Then your tableView:didSelectRowAtIndexPath: should look like this
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[self.tableView deselectRowAtIndexPath:indexPath animated:YES];
MyObject *myObject = [self.fetchedResultsController objectAtIndexPath:indexPath];
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
if ([myObject.optionSelected boolValue] == NO) {
[myObject setOptionSelected:[NSNumber numberWithBool:YES]];
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
[selectedCellPaths addObject:indexPath];
} else {
[myObject setOptionSelected:[NSNumber numberWithBool:NO]];
[cell setAccessoryType:UITableViewCellAccessoryNone];
if ([selectedCellPaths containsObject:indexPath]) {
[selectedCellPaths removeObject:indexPath];
}
}
// Now we're going to remove all but the cell path that is actually selected.
NSMutableArray *cellsToRemove = [[NSMutableArray alloc] init];
for (NSIndexPath *selectedCellIndexPath in selectedCellPaths) {
if ([selectedCellIndexPath compare:indexPath] != NSOrderedSame && selectedCellIndexPath.section == indexPath.section) {
// deselect cell at selectedCellPath
[cellsToRemove addObject:selectedCellIndexPath];
}
}
[selectedCellPaths removeObjectsInArray:cellsToRemove];
}
Note I have just put in a comment where you would want to deselect the actual cell at the cell path that is not selected. You need to fill that code in yourself.
I haven't tested this code, just modified what you had in TextMate but it should work barring minor changes.

Related

Call something based on UITableView rows selected, in an IBAction

I just saw a post about selecting multiple UITableView rows and based on which row/rows are selected, something will happen when you press a button linked to an IBAction.
It's an interesting question and I've played around with it, but now I'm stuck a bit.
As you can see I have a NSMutableArray called selectedIndexes, and the selected row/rows are shown in the console using a NSLog. This works fine:
- (IBAction)doSomethingWithSelectedRows:(id)sender {
for (NSNumber *data in self.selectedIndexes) {
NSLog(#"Row %ld is selected.", (long)[data integerValue] +1);
}
if (WHAT SHOULD BE PUT HERE?) {
}
//Do whatever you want here.
}
The question is, what should be put in that if statement above if you want this to happen:
if (row 2 and row 1 are selected {
//Run this code.
}
UPDATE:
Here's more code:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
if ([selectedCell accessoryType] == UITableViewCellAccessoryNone) {
[selectedCell setAccessoryType:UITableViewCellAccessoryCheckmark];
[_selectedIndexes addObject:[NSNumber numberWithInteger:indexPath.row]];
} else {
[selectedCell setAccessoryType:UITableViewCellAccessoryNone];
[_selectedIndexes removeObject:[NSNumber numberWithInteger:indexPath.row]];
}
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
- (IBAction)doSomethingWithRowsSelected:(id)sender {
for (NSNumber *data in self.selectedIndexes) {
NSLog(#"Row %ld is selected.", (long)[data integerValue] +1);
}
}
While you can use an array, as you do, an NSMutableIndexSet is a much better data structure for this task. It allows you to check whether a given index is in the set without having to iterate through all of the objects.
#property (strong,nonatomic) NSMutableIndexSet *selectedRows;
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSUInteger row = indexPath.row;
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
if ([self.selectedRows containsIndex:row]) {
[self.selectedRows removeIndex:row];
[selectedCell setAccessoryType:UITableViewCellAccessoryNone];
} else {
[self.selectedRows addIndex:indexPath.row];
[selectedCell setAccessoryType:UITableViewCellAccessoryCheckmark];
}
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
Now you can easily check if any two rows are selected:
- (IBAction)doSomethingWithRowsSelected:(id)sender {
if ([self.selectedRows containsIndex:1] && [self.selectedRows containsIndex:2]) {
// Do whatever
}
}
Also, don't forget to set the accessory type in cellForRowAtIndexPath based on [self.selectedRows containsIndex:indexPath.row] otherwise your checkmarks will be wrong when you scroll.
Here is what I will do,
1st, get the array of selected rows by using indexPathsForSelectedRows,
2nd, iterate the array to check if if indexPath.row is 1 or 2.
3rd, if your if statement's condition is true, then do ...

why selection of a cell in one section affect to cells in other sections in iOS tableview, objective c [duplicate]

I have a table view with 5 sections and I have set the tableview selection to multiple. Each section have different number of rows. What I want is to set that the user can select only one cell from each section(in my table user can select any number of cells).
ex: 5 cells from 5 sections.
It should be impossible to select more than one cell from any section. If user select another cell from same section, previously selected cell should be deselected. How can I do this. This is a sample implementation of didSelectRowAtIndexPath.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
HoteldetalcelloneTableViewCell *cellone = (HoteldetalcelloneTableViewCell *)[self.detailtableView cellForRowAtIndexPath:indexPath];
HoteldetailcelltwoTableViewCell *celltwo = (HoteldetailcelltwoTableViewCell *)[self.detailtableView cellForRowAtIndexPath:indexPath];
//I have implement for two sections to test.
if(indexPath.section == 0)
{
HotelDetailsone *secone = [roomonearray objectAtIndex:indexPath.row];
HoteldetailsforBooking *book = [HoteldetailsforBooking new];
if([secone.offerallow isEqualToString:#"True"])
{
celltwo.selectedsignLabel.hidden = NO;
}
else
{
cellone.selectedsignLabelone.hidden = NO;
}
// [self.detailtableView reloadData];
NSLog(#"price for room 1 : %#", secone.itempriceText);
}
else
{
HotelDetailsone *sectwo = [roomtwoarray objectAtIndex:indexPath.row];
HoteldetailsforBooking *book = [HoteldetailsforBooking new];
if([sectwo.offerallow isEqualToString:#"True"])
{
celltwo.selectedsignLabel.hidden = NO;
}
else
{
cellone.selectedsignLabelone.hidden = NO;
}
// [self.detailtableView reloadData];
NSLog(#"price for room 1 : %#", sectwo.itempriceText);
}
}
You need to keep track on the selection of cell. So you need to store selected indexpath in array.
in ViewController.h declare property like this
#property(nonatomic,strong) NSMutableDictionary *selectionData;
Now in ViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
self.selectionData=[[NSMutableDictionary alloc]init];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
TestTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"mycell"];
if ([self.selectionData objectForKey:[NSString stringWithFormat:#"%ld",(long)indexPath.section] ] != nil) {
NSMutableArray *sectionData=[[self.selectionData objectForKey:[NSString stringWithFormat:#"%ld",(long)indexPath.section]] mutableCopy];
if (![sectionData containsObject:[NSNumber numberWithLong:indexPath.row]])
{
cell.accessoryType = UITableViewCellAccessoryNone;
cell.numberlabel.text = #"2";
}
else
{
cell.numberlabel.text = #"***";
cell.accessoryType=UITableViewCellAccessoryCheckmark;
}
}
else
{
cell.numberlabel.text = #"2";
cell.accessoryType = UITableViewCellAccessoryNone;
}
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"selected section :%li ---> selected row :%li",(long)indexPath.section, (long)indexPath.row);
[self handleSelectionForSection:indexPath.section row:indexPath.row];
[self.tablev reloadData];
}
-(void)handleSelectionForSection:(long)sectionIndex row:(long)rowIndex
{
if ([self.selectionData objectForKey:[NSString stringWithFormat:#"%ld",sectionIndex] ] != nil) {
NSMutableArray *sectionData=[[self.selectionData objectForKey:[NSString stringWithFormat:#"%ld",sectionIndex]] mutableCopy];
if (![sectionData containsObject:[NSNumber numberWithLong:rowIndex]])
{
//removing previous selected rows
[sectionData removeAllObjects];
[sectionData addObject:[NSNumber numberWithLong:rowIndex]];
[self.selectionData setObject:sectionData forKey:[NSString stringWithFormat:#"%ld",sectionIndex]];
}
else
{
//cell you tapped is already selected,
// you can deselect it by removing object
//if you dont want to deselect it comment following lines
[sectionData removeObject:[NSNumber numberWithLong:rowIndex]];
[self.selectionData setObject:sectionData forKey:[NSString stringWithFormat:#"%ld",sectionIndex]];
}
}
else
{
//section key not available so we need to create it
NSMutableArray *sectionData=[[NSMutableArray alloc]init];
[sectionData addObject:[NSNumber numberWithLong:rowIndex]];
[self.selectionData setObject:sectionData forKey:[NSString stringWithFormat:#"%ld",sectionIndex]];
}
NSLog(#"All Selection : %#",self.selectionData);
}
Your numberOfRowsInSection, numberOfSectionsInTableView and titleForHeaderInSection will remain same.
Let me know if you have any query.
You can set selection property of tableview from interface builder. Select your tableview in IB and then select attribute inspector and setsingle selectiontoselection` property like below screenshot.
Or you can set programattically,
self.tableView.allowsMultipleSelection = NO;
Update :
If you want single selection per section then you can implement willSelectRowAtIndexPath as below,
- (NSIndexPath*)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath*)indexPath {
for ( NSIndexPath* selectedIndexPath in tableView.indexPathsForSelectedRows ) {
if ( selectedIndexPath.section == indexPath.section )
[tableView deselectRowAtIndexPath:selectedIndexPath animated:NO] ;
}
return indexPath ;
}
In this case you should allow multiple selection in tableview i think.
Reference : Answer of John Sauer
Looks like you are updating celltwo / cellone selectedsignLabel.hidden on table selection. so #Lion solution will not working. You have to save the last selected index using below code :
#property (nonatomic, strong) NSMutableDictionary *selectedIndexPathDict;
// in viewDidLoad:
self.tableView.allowsMultipleSelection = YES;
self.selectedIndexPathDict = [[NSMutableDictionary alloc] init];
//In table view delegate.
- (NSIndexPath*)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath*)indexPath {
NSString *indexSection = [NSString stringWithFormat:#"%ld", (long)indexPath.section];
NSIndexPath *indexPath1 = self.selectedIndexPathDict[indexSection];
if ( indexPath1) {
HotelDetailsone *secone = [roomonearray objectAtIndex:indexPath.row];
secone.offerallow ^= YES; //toggle bool value
// update new selected index path.
[self.selectedIndexPathDict setObject:indexPath forKey:indexSection];
//reload previous selected cell.
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(),^{
[tableView beginUpdates];
[tableView reloadRowsAtIndexPaths:#[indexPath1] withRowAnimation:UITableViewRowAnimationFade];
[tableView endUpdates];
});
} else {
//initialise selected index path
self.selectedIndexPathDict[indexSection] = indexPath;
}
[tableView deselectRowAtIndexPath:indexPath animated:NO] ;
return indexPath ;
}
I have not update the complete working code. But this is the way to achieve. You can also use the userdefault instead of self.selectedIndexPathDict.

remove objects of selected row

hey i have created a table view with multiple selection and checkmark accessory which users can tap on and select relevant rows in table... retailerid and retailernaem of individual selection will be stored in NSMutableDictionary and all dictionaries in return will be stored in NSMutableArray... i have done this till now
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
if ([selectedCell accessoryType] == UITableViewCellAccessoryNone) {
[selectedCell setAccessoryType:UITableViewCellAccessoryCheckmark];
NSMutableDictionary *theDictionary = [[NSMutableDictionary alloc] init];
[theDictionary setObject:[[BrandsArray valueForKey:#"RetailerID"] objectAtIndex:indexPath.row] forKey:#"id"];
[theDictionary setObject:[[BrandsArray valueForKey:#"RetailerName"] objectAtIndex:indexPath.row] forKey:#"name"];
[selectedIndexes addObject:theDictionary];
}
else {
[selectedCell setAccessoryType:UITableViewCellAccessoryNone];
NSLog(#"this is deselected row %#",[selectedIndexes objectAtIndex:indexPath.row]);
NSMutableDictionary *dictionary = [selectedIndexes objectAtIndex:indexPath.row];
[selectedIndexes removeObject:dictionary];
dictionary = nil;
}
[tableView deselectRowAtIndexPath:indexPath animated:NO];
}
now problem is in the else block... its not removing objects from randomly selected row...
for example if i select first row and then deselect the same it works fine but when i select the last row and then deselect the same app crash..
Since my other answer dealt with multiple sections, I will provide a simpler, single section answer here
First, declare a property for your selection state -
#property (strong,nonatomic) NSMutableIndexSet *selectStates;
Initialise it in viewDidLoad
self.selectStates=[NSMutableIndexSet new];
The use it in didSelectRowAtIndexPath -
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
if ([self.selectStates containsIndex:[indexPath.row]) {
[selectedCell setAccessoryType:UITableViewCellAccessoryNone];
[self.selectStates removeIndex:indexPath.row];
} else {
[selectedCell setAccessoryType:UITableViewCellAccessoryCheckmark];
[self.selectStates addIndex:indexPath.row];
}
[tableView deselectRowAtIndexPath:indexPath animated:NO];
}
You will also need to check the selectedStates in cellForRowAtIndexPath to set the correct accessory when the cell is scrolled back into view. Just add the snippet -
if ([self.selectStates containsIndex:[indexPath.row]) {
[cell setAccessoryType:UITableViewCellAccessoryNone];
} else {
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
}
If you need the ability to easily insert and delete rows then you can use an NSMutableSet instead of an NSIndexSet - just store the data source object. If you do allow deletion you need to make sure that the object is removed from the set, if necessary, when the row is deleted.
First, declare a property for your selection state -
#property (strong,nonatomic) NSMutableSet *selectStates;
Initialise it in viewDidLoad
self.selectStates=[NSMutableSet new];
The use it in didSelectRowAtIndexPath -
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
Brand *brand=(Brand *)[BrandsArray objectAtIndex:indexPath.row]; // Change "Brand" to the appropriate object class
if ([self.selectStates containsObject:brand) {
[selectedCell setAccessoryType:UITableViewCellAccessoryNone];
[self.selectStates removeObject:brand];
} else {
[selectedCell setAccessoryType:UITableViewCellAccessoryCheckmark];
[self.selectStates addObject:brand];
}
[tableView deselectRowAtIndexPath:indexPath animated:NO];
}
You will also need to check the selectedStates in cellForRowAtIndexPath to set the correct accessory when the cell is scrolled back into view. Just add the snippet -
if ([self.selectStates containsObject:brand) {
[cell setAccessoryType:UITableViewCellAccessoryNone];
} else {
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
}
The problem is the way you use the array.
Let's say you select the last element from a table view with 10 cells. Then the array size is 1, but when you select again the last row, [selectedIndexes objectAtIndex:indexPath.row]; is trying to access the element with index 9 in the array, which does not exist at the moment.
Try to implement something like this:
NSInteger ARRAY_INITIAL_SIZE = 100;
NSMutableArray *selectedIndexes = [NSMutableArray arrayWithCapacity:ARRAY_INITIAL_SIZE];
for (NSInteger i = 0; i < ARRAY_INITIAL_SIZE; ++i) {
selectedIndexes[i] = [NSNull null];
}
Make selectedIndexes to be a property in your View Controller class, and whenever you use it, put self.selectedIndexes instead.
In the didSelectRow: atIndexPath: method, the first line is recommended to be:
[tableView deselectRowAtIndexPath:indexPath animated:NO];
Then, write the code:
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
if ([selectedCell accessoryType] == UITableViewCellAccessoryNone) {
selectedCell.accessoryType = UITableViewCellAccessoryCheckmark;
NSMutableDictionary *theDictionary = [NSMutableDictionary dictionary];
[theDictionary setObject:[[BrandsArray valueForKey:#"RetailerID"] objectAtIndex:indexPath.row] forKey:#"id"];
[theDictionary setObject:[[BrandsArray valueForKey:#"RetailerName"] objectAtIndex:indexPath.row] forKey:#"name"];
[selectedIndexes replaceObjectAtIndex:indexPath.row withObject:theDictionary];
} else {
selectedCell.accessoryType = UITableViewCellAccessoryNone;
[selectedIndexes replaceObjectAtIndex:indexPath.row withObject:[NSNull null]];
}
I hope it helps you. Let me know.

Having trouble with Multiple Selection in UITableview

I've been trying to selection of cell like
Same As Checkbox To select elements from object array
Here is my code. Please guide me.. Thanks in advance
#import <UIKit/UIKit.h>
#interface CheckAllListViewController : UIViewController <UITableViewDataSource,UITableViewDelegate>
{
IBOutlet UITableView *_myTable;
NSMutableArray *_myArray;
NSMutableArray *_selectedArray;
}
#property(nonatomic,retain) UITableView *myTable;
#property(nonatomic,retain)NSMutableArray *myArray;
#property(nonatomic,retain)NSMutableArray *selectedArray;
-(void)checkmarkAll;
-(void)UnChceckAll;
CheckAllListViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
_myArray=[[NSMutableArray alloc]initWithObjects:#"Check All",#"1",#"2",#"3",#"4",#"5",#"6",#"7",#"8",#"9",#"10" ,nil];
_selectedArray=[[NSMutableArray alloc]init];
// Do any additional setup after loading the view from its nib.
}
#pragma mark -UITableViewDelegates & Datasource
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if (cell.accessoryType == UITableViewCellAccessoryNone)
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
[self.selectedArray addObject:[self.myArray objectAtIndex:indexPath.row]];
//if 'all' row is selected then check all rows
if([[self.myArray objectAtIndex:indexPath.row] isEqualToString:#"Check All"])
{
[self checkmarkAll];
}
}
else if (cell.accessoryType == UITableViewCellAccessoryCheckmark)
{
cell.accessoryType = UITableViewCellAccessoryNone;
[self.selectedArray removeObject:[self.myArray objectAtIndex:indexPath.row]];
if([[self.myArray objectAtIndex:indexPath.row] isEqualToString:#"Check All"])
{
[self UnChceckAll];
[self.selectedArray removeAllObjects];
}
else if([self.selectedArray containsObject:#"Check All"])
{
[self checkmarkAll];
[self.selectedArray removeAllObjects];
cell.accessoryType = UITableViewCellAccessoryNone;
[self.selectedArray addObject:[self.myArray objectAtIndex:indexPath.row]];
}
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [_myTable dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
if([self.selectedArray count])
{
if([self.selectedArray containsObject:[self.myArray objectAtIndex:indexPath.row]] || [self.selectedArray containsObject:#"Check All"])
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
}
cell.textLabel.text=[_myArray objectAtIndex:indexPath.row];
// [self configureCell:cell atIndexPath:indexPath];
return cell;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return _myArray.count;
}
-(void)checkmarkAll
{
for (int i=0;i<[self.myArray count] ; i++)
{
NSIndexPath *myIdx=[NSIndexPath indexPathForRow:i inSection:0];
UITableViewCell *cell=[self.myTable cellForRowAtIndexPath:myIdx];
cell.accessoryType=UITableViewCellAccessoryCheckmark;
}
}
-(void)UnChceckAll
{
for(int i=0;i<[self.myArray count];i++)
{
NSIndexPath *myIndexPath = [NSIndexPath indexPathForRow:i inSection:0];
UITableViewCell *cell = [self.myTable cellForRowAtIndexPath:myIndexPath];
cell.accessoryType = UITableViewCellAccessoryNone;
}
}
I've used this tutorial -http://iphonediscoveries.blogspot.in/2013/10/creating-inclusive-list-in-uitableview.html
I want to achieve :
1 Add an option for the user to be able to select all rows when ‘all’ is selected.
2 When the ‘all’ is checked I want all rows checkmarked, and all checkmarks removed when 'all' is unchecked.
3 When ‘all’ is checked, and all rows are checkmarked, if at that time a row is clicked, then check marks in all other rows should be removed (including ‘all’) and only that row should contain the checkmark.
4 Should not forget Selection After calling and scrolling UITableview
UPDATE
-My Following code gives me check all functionality & Uncheck All Functionality .
Lets say I've chosen all row by selecting check all now,If I'd choose any row randomly Should remove tick from current selected element & as well should remove tick from first element i.e #"Check All"
-same for uncheck functionality
Not sure if I get what the problem is, but I would change the checkAll and uncheckAll methods to change the selectedArray and reload the tableview:
-(void)checkmarkAll
{
self.selectedArray = [NSMutableArray arrayWithArray:self.myArray];
[self.tableView reloadData];
}

How do you select uitableview rows programmatically

I am trying to achive a email like select all functionality in uitableview where on same button tap user can checkmark or remove all checkmark and additionally user can also select/deselect rows(on didSelectRowAtIndexPath). I tried to do but its not working properly, here is my code.
- (IBAction)selectAll:(id)sender
{
if(myBoolean)
{
for (NSInteger s = 0; s < self.iTable.numberOfSections; s++)
{
for (NSInteger r = 0; r < [self.iTable numberOfRowsInSection:s]; r++)
{
[[self.iTable cellForRowAtIndexPath:[NSIndexPath indexPathForRow:r inSection:s]] setAccessoryType:UITableViewCellAccessoryNone];
}
}
myBoolean = NO;
[_selectUnselectButton setTitle:#"Select all Friends" forState:UIControlStateNormal];
}
else
{
for (NSInteger s = 0; s < self.iTable.numberOfSections; s++)
{
for (NSInteger r = 0; r < [self.iTable numberOfRowsInSection:s]; r++)
{
[[self.iTable cellForRowAtIndexPath:[NSIndexPath indexPathForRow:r inSection:s]] setAccessoryType:UITableViewCellAccessoryCheckmark];
NSLog(#"%d-%d",s,r);
}
}
myBoolean = YES;
[_selectUnselectButton setTitle:#"Unselect all Friends" forState:UIControlStateNormal];
}
}
-(void)tableView:(UITableView *)tableView_ didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView_ cellForRowAtIndexPath:indexPath];
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
if (cell.accessoryType == UITableViewCellAccessoryCheckmark)
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
else
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
}
I wrote a sample code that I adapted to your needs.
Basically it is
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *unifiedID = #"aCellID";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:unifiedID];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:unifiedID];
}
cell.textLabel.text = [self.states objectAtIndex:indexPath.row];
//if the indexPath was found among the selected ones, set the checkmark on the cell
cell.accessoryType = ([self isRowSelectedOnTableView:tableView atIndexPath:indexPath]) ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *state = [self.states objectAtIndex:indexPath.row];
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if([self isRowSelectedOnTableView:tableView atIndexPath:indexPath]){
[self.selectedCells removeObject:indexPath];
[self.selecedStates removeObject:state];
cell.accessoryType = UITableViewCellAccessoryNone;
} else {
[self.selectedCells addObject:indexPath];
[self.selecedStates addObject:state];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
NSLog(#"%#", self.selecedStates);
}
-(BOOL)isRowSelectedOnTableView:(UITableView *)tableView atIndexPath:(NSIndexPath *)indexPath
{
return ([self.selectedCells containsObject:indexPath]) ? YES : NO;
}
- (IBAction)selectAll:(id)sender {
[self.selecedStates removeAllObjects];
[self.selectedCells removeAllObjects];
NSUInteger numberOfSections = [self.tableView numberOfSections];
for (NSUInteger s = 0; s < numberOfSections; ++s) {
NSUInteger numberOfRowsInSection = [self.tableView numberOfRowsInSection:s];
for (NSUInteger r = 0; r < numberOfRowsInSection; ++r) {
NSIndexPath *idxPath = [NSIndexPath indexPathForRow:r inSection:s];
[self.selectedCells addObject:idxPath];
[self.selecedStates addObject:self.states[idxPath.row]];
}
}
[self.tableView reloadData];
}
- (IBAction)deselectAll:(id)sender {
[self.selecedStates removeAllObjects];
[self.selectedCells removeAllObjects];
[self.tableView reloadData];
}
- (IBAction)toggleAll:(id)sender {
if ([self.states count] == [self.selecedStates count]) {
[sender setTitle:#"select all"];
[self deselectAll:sender];
} else {
[sender setTitle:#"deselect all"];
[self selectAll:sender];
}
}
in action:
You are calling
[[self.iTable cellForRowAtIndexPath:[NSIndexPath indexPathForRow:r inSection:s]] setAccessoryType:UITableViewCellAccessoryNone];
for every row in every section within the tableView. if you have many row, this is ver inefficient, as it will deal with rows not on the screen. But this is not needed. just put every selected index path into an array and tell the tableView to reload. This will reload the visible cells and due to the implementation of -tableView:cellForRowAtIndexPath: cells wfor new rows will be correctly re-conigured.
Setting the accessory view needs to happen inside the tableView:cellForRowAtIndexPath: method. When you want to change the accessories from outside, the outside method needs to change the model first to indicate that check marks must be placed in certain cells, and then call reloadData on the UITableView.
One way to store what cells are checked is an array of NSIndexSet objects - one index set per section. In the example below I show code for a single section, but you should get an idea of how to make multiple sections work.
// This variable needs to be declared in a place where your data source can get it
NSMutableIndexSet *selected;
// You need to initialize it in the designated initializer, like this:
selected = [[NSMutableIndexSet alloc] init];
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
if ([selected containsIndex:indexPath.row]) {
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
} else {
[cell setAccessoryType:UITableViewCellAccessoryNone];
}
// Do the rest of your code
return cell;
}
Now in the code where you want to set rows selected or unselected you just need to call [selected addIndex:rowToSelect] or [selected removeIndex:rowToUnselect], and call your table's reloadData.
Use selectRowAtIndexPath:animated:scrollPosition: to select a row
and deselectRowAtIndexPath:animated: to deselect a row.
For more read the UITableView docs
Try this code instead of your old one
- (IBAction)selectAll:(id)sender
{
if(myBoolean)
{
for (NSInteger s = 0; s < self.iTable.numberOfSections; s++)
{
for (NSInteger r = 0; r < [self.iTable numberOfRowsInSection:s]; r++)
{
[self.iTable selectRowAtIndexPath:[NSIndexPath indexPathForRow:r inSection:s]] animated:YES scrollPosition:UITableViewScrollPositionNone];
}
}
myBoolean = NO;
[_selectUnselectButton setTitle:#"Select all Friends" forState:UIControlStateNormal];
}
else
{
for (NSInteger s = 0; s < self.iTable.numberOfSections; s++)
{
for (NSInteger r = 0; r < [self.iTable numberOfRowsInSection:s]; r++)
{
[self.iTable selectRowAtIndexPath:[NSIndexPath indexPathForRow:r inSection:s]] animated:YES scrollPosition:UITableViewScrollPositionNone];
NSLog(#"%d-%d",s,r);
}
}
myBoolean = YES;
[_selectUnselectButton setTitle:#"Unselect all Friends" forState:UIControlStateNormal];
}
}
-(void)tableView:(UITableView *)tableView_ didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView_ cellForRowAtIndexPath:indexPath];
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
if (cell.accessoryType == UITableViewCellAccessoryCheckmark)
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
else
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
}
You can follow these steps to implement this,
1) You should have a mutable array to store indexpaths
2) What you can do is, when you tap Check All or Uncheck All, do add or remove all indexpaths to/from array (which you've), reload table for update changes
3) In - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath datasource method, check into array using if([array containsObject:indexPath]), if exist mark it checked or unchecked
4) In - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath delegate method, you should check for already existence of indexpath tapped into array, as you've did in 3rd step, and add or remove indexpaths as per the condition, reload table for update changes
Take another NSMutableArray as SelectedArray
in didSelectRowAtIndexPath row You can Add remove objects from SelectedArray.
You can select a UITableViewCell calling UITableViews selectRowAtIndexPath method:
[yourtable selectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]
animated:NO
scrollPosition:UITableViewScrollPositionTop];
Put for loop for selectedArray to putcheckmark only in selected cells or All cells.
check my accepted answer here : Need to create a select all button for UITableView and add selections to an array in iOS
Xcode 8x
Swift 3x
Select Row
let indexPath = IndexPath(row: 0, section: 0)
mytableView.selectRow(at: indexPath, animated: true, scrollPosition: .bottom)
myTableView.delegate?.tableView!(myTableView, didSelectRowAt: indexPath)
DeSelect Row
let deselectIndexPath = IndexPath(row: 7, section: 0)
myTableView.deselectRow(at: deselectIndexPath, animated: true)
myTableView.delegate?.tableView!(tblView, didDeselectRowAt: indexPath)
you can do something like this:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[self doSomethingWithRowAtIndexPath:indexPath];
}

Resources