Multiple selection with multiple sections in UItableview - ios

If I select the first indexPath of first section , all the first indexPath of different sections gets selected like the image. How to rectify it?
if ([arraySelectedValue‌​s containsObject:array‌​StateNames[indexPath.‌​row]]) {
cell.imageCheck.imag‌​e =[UIImage imageNamed:#"check"]‌​;
} else {
cell.imageCheck.imag‌​e =[UIImage imageNamed:#"uncheck‌​"];
}

Change your code to the following.
if ([arraySelectedValue‌​s containsObject:indexPath])
{
cell.imageCheck.imag‌​e =[UIImage imageNamed:#"check"]‌​;
}
else
{
cell.imageCheck.imag‌​e =[UIImage imageNamed:#"uncheck‌​"];
}
and in didSelectRow method write the below code
if ([arraySelectedValues containsObject:indexPath])
{
[arraySelectedValues removeObject:indexPath];
}
else
{
[arraySelectedValues addObject:indexPath];
}
and reload the section or row

For this you need create a global arr to hold selected indexPath in your h file
NSMutable *arrSelectedIndex;
in your didSelectItemAtIndexPath you need to write below code.
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
[self selectDeselectIndexpath:indexPath];
[collectionView reloadData];
}
// this method is used to toggle between selection and deselection
-(void) selectDeselectIndexpath : (NSIndexPath *) indexPath{
for (int i=0; i < arrSelectedIndex.count; i++) {
NSIndexPath *index = [arrSelectedIndex objectAtIndex:i];
if (index.row == indexPath.row && index.section == indexPath.section) {
[arrSelectedIndex removeObject:index];
return ;
}
}
[arrSelectedIndex addObject:indexPath];
}
// this method is used to select any indexPath
-(void) selectIndexpath : (NSIndexPath *) indexPath{
for (int i=0; i < arrSelectedIndex.count; i++) {
NSIndexPath *index = [arrSelectedIndex objectAtIndex:i];
if (index.row == indexPath.row && index.section == indexPath.section) {
return ; // This means indexPath already selected
}
}
[arrSelectedIndex addObject:indexPath];
}
// this method is used to deselect any indexPath
-(void) deselectIndexpath : (NSIndexPath *) indexPath{
for (int i=0; i < arrSelectedIndex.count; i++) {
NSIndexPath *index = [arrSelectedIndex objectAtIndex:i];
if (index.row == indexPath.row && index.section == indexPath.section) {
[arrSelectedIndex removeObject:index];
return ; // Indexpath found and remove from array
}
}
// Reaching over here means this indexpath not selected;
}
You can use any the above method as per you need.

Related

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.

Keep selected state of UITableViewCells when scrolling

I am trying to keep the selected state of multiple cells on a didSelectRowAtIndexPath method. I have an edit button that I've set up that loops through every cell to select each field on my UITableView.
Here is the code for the edit button on tap that selects all my rows.
- (IBAction)editButtonTapped:(id)sender {
for (int i = 0; i < self.caseDataTableView.numberOfSections; i++) {
for (NSInteger r = 0; r < [self.caseDataTableView numberOfRowsInSection:i]; r++) {
[self tableView:caseDataTableView didSelectRowAtIndexPath:[NSIndexPath indexPathForRow:r inSection:i]];
}
}
}
When calling the didSelectRowAtIndexPath method, it does the following code.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
OKOperatieNoteTableViewCell *cell = (OKOperatieNoteTableViewCell *)[self.caseDataTableView cellForRowAtIndexPath:indexPath];
cell.cellIndexPath = indexPath;
[cell hideLabelAndShowButtons];}
Incase you were wondering here is the hideLabelAndShowButtons method.
- (void)hideLabelAndShowButtons {
self.caseDataKeyLabel.hidden = NO;
if (!self.disabled) {
self.caseDataValueLabel.hidden = YES;
self.textField.hidden = NO;
if ([self.inputType isEqualToString:#"switcher"] || [self.inputType isEqualToString:#"multiselect"] || [self.inputType isEqualToString:#"picker"] || [self.inputType isEqualToString:#"DatePicker"] || [self.inputType isEqualToString:#"selectContact"]) {
self.button.hidden = NO;
}else {
self.button.hidden = YES;
}
}
self.caseDataDescriptionTextView.hidden = YES;}
Now at this point, I have all my rows selected. If I scroll down and then back up the selection of these rows is not there anymore. Now I'm aware when you go in and out of the view, the cellForRowAtIndexPath method recreates these cells. The following is my cellForRowAtIndexPath method.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = #"caseData";
OKOperatieNoteTableViewCell * cell = [[OKOperatieNoteTableViewCell alloc]init];
cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
if (indexPath.row < _procedureVariables.count) {
if ([[[_caseDataArray objectAtIndex:indexPath.row] valueForKey:#"key"] isEqualToString:#"Procedure"]) {
[cell setLabelsWithKey:[[_caseDataArray objectAtIndex:indexPath.row] valueForKey:#"key"] AndValue:[self.model valueForKey:#"var_procedureName"]];
}else {
[cell setLabelsWithKey:[[_caseDataArray objectAtIndex:indexPath.row] valueForKey:#"key"] AndValue:[[_caseDataArray objectAtIndex:indexPath.row] valueForKey:#"value"]];
}
OKProcedureTemplateVariablesModel *variableModel = _procedureVariables[indexPath.row];
cell.variable = variableModel.value;
[cell showLabelAndHideButtons];
cell.delegate = self;
[cell setUpCellType];
} else if (indexPath.row == _procedureVariables.count) {
NSString *text = [NSString stringWithFormat:#"%# \n\n %#", [_templateDictionary objectForKey:#"indicationText"], [_templateDictionary objectForKey:#"procedureText"] ];
[cell showDescription:text];
NSLog(#"cell.caseDataDescriptionTextView.font.fontName = %#", cell.caseDataDescriptionTextView.font.fontName);
}
cell.procedureID = _procedureID;
[tableView setContentInset:UIEdgeInsetsMake(1.0, 0.0, 0.0, 0.0)];
return cell;
}
I'm just trying to figure out how to keep the selected state of these cells once the cellForRowAtIndexPath method is called. Any suggestions are welcomed.
i tried to simulate your situation, created a customCell and saved the indexpaths of selectedRows in my custom selectedPaths mutable array(initialized in viewDidLoad).
After every click i removed or added related indexpath to my array.
it worked for my case. Hope it helps.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"caseData";
NOTableViewCell *cell = (NOTableViewCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil)
{
NSLog(#"new cell created for row %d", (int)indexPath.row);
cell = [[[NSBundle mainBundle] loadNibNamed:#"NOTableViewCell" owner:self options:nil] objectAtIndex:0];
}
if ([selectedPaths indexOfObject:indexPath] != NSNotFound) // this cell is in selected state.
{
[cell.textLabel setText:#"This cell selected"];//selected state job.
return cell;
}
[cell.textLabel setText:[NSString stringWithFormat:#"%d", (int)indexPath.row]];
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([selectedPaths indexOfObject:indexPath] != NSNotFound) {
[selectedPaths removeObject:indexPath];
}
else{
[selectedPaths addObject:indexPath];
}
//[tableView reloadData];
[tableView reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationNone];//instead of reloading all just reload clicked cell.
}
You need to update the cell to selected and not selected explicitly in both directions in cellForRowAtIndexPath.
If not, the recycled cells will just show the value of the cell the cell was last used for until you change it.
While you are invoking the delegate method in order to call hideLabelAndShowButtons, you aren't telling the table view that you have selected the row;
- (IBAction)editButtonTapped:(id)sender {
for (int i = 0; i < self.caseDataTableView.numberOfSections; i++) {
for (NSInteger r = 0; r < [self.caseDataTableView numberOfRowsInSection:i]; r++) {
NSIndexPath *path=[NSIndexPath indexPathForRow:r inSection:i];
[caseDataTableView selectRowAtIndexPath:path animated:NO scrollPosition:UITableViewScrollPositionNone];
[self tableView:caseDataTableView didSelectRowAtIndexPath:path];
}
}
}
Also, you aren't using the cell selection state in cellForRowAtIndexPath, so you probably need to change some code there too, but I am not sure what the relationship is between selected state and how you want to render the cell.

Store Cells with switch on from a Tableview

What I want is to generate a sub-contact using properties form an existing CNContact object.
I got the CNContact object from CNContactPickerViewController and display all properties in a tableview.
The tableviewcell is embedded with switch. I have a preview button on the navigation item, when the button is pressed, if the switch in a property is on, this property should be stored in a new CNMutableContact.
My issue is: If the Contact has too many properties, I cannot get the off-screen properties stored. Is there a way to solve this problem.
part of the code to get sub-contact:
+(CNMutableContact*)newContactWithSelectedFieldInTableView:(UITableView*)tableView FromContact:(CNContact*)contact
{
CNMutableContact* aContact = [[CNMutableContact alloc]init];
//get all indexPath from tableview
NSMutableArray* indexPathArr = [[NSMutableArray alloc]init];
NSInteger nSections = [tableView numberOfSections];
for (int j=0; j<nSections; j++) {
NSInteger nRows = [tableView numberOfRowsInSection:j];
for (int i=0; i<nRows; i++) {
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:i inSection:j];
[indexPathArr addObject:indexPath];
}
}
//selected phone numbers
//go through indexPath
for (NSIndexPath* path in indexPathArr)
{
UITableViewCell* nameCell = [tableView cellForRowAtIndexPath:path];
UISwitch *mySwitch = (UISwitch *)nameCell.accessoryView;
switch (path.section)
{
case basicInfoSection://basic info section (name,company,department,title)
{
int row = 0;
if(path.row==row)
{
if(mySwitch.on)
{
aContact.givenName = contact.givenName;
aContact.middleName = contact.middleName;
aContact.familyName = contact.familyName;
}
}
if(![contact.organizationName isEqualToString:#""])
{row += 1;
if(path.row==row)//company row
{
//store company
if(mySwitch.on)
aContact.organizationName = contact.organizationName;
}
}
if(![contact.departmentName isEqualToString:#""])
{row += 1;
if(path.row==row)//department row
{
//store department
if(mySwitch.on)
aContact.departmentName = contact.departmentName;
}
}
if(![contact.jobTitle isEqualToString:#""])
{row += 1;
if(path.row==row)//jobTitle row
{
//store job Title
if(mySwitch.on)
aContact.jobTitle = contact.jobTitle;
}
}
}
break;
case phoneSection:
{
if(mySwitch.on)
{
aContact.phoneNumbers = [aContact.phoneNumbers arrayByAddingObject:contact.phoneNumbers[path.row]];
}
}
break;
I come up with a solution and it work fine for now, some code are listed below:
1# create a subclass of UISwitch
#import <UIKit/UIKit.h>
#interface SwitchWithIndex : UISwitch
#property (strong ,nonatomic) NSIndexPath* indexPath;
#end
2# create a dictionary that record indexPath with switch state and in view did load, loop datasource(the CNContact) for all possible indexPath according to the demand tableview layout.
for(NSInteger section=0; section<7; section++)
{
switch (section) {
{
//section 1 basic info(name, company, department, job title)
case basicInfoSection:
{int row =0;
NSIndexPath* indexPath = [NSIndexPath indexPathForRow:row inSection:section];
[_switchStateAtIndex setObject:boolNumber forKey:indexPath];
if(![_contact.organizationName isEqualToString:#""])
{row += 1;
NSIndexPath* indexPath = [NSIndexPath indexPathForRow:row inSection:section];
[_switchStateAtIndex setObject:boolNumber forKey:indexPath];
}
if(![_contact.departmentName isEqualToString:#""])
{row += 1;
NSIndexPath* indexPath = [NSIndexPath indexPathForRow:row inSection:section];
[_switchStateAtIndex setObject:boolNumber forKey:indexPath];
}
if(![_contact.jobTitle isEqualToString:#""])
{row += 1;
NSIndexPath* indexPath = [NSIndexPath indexPathForRow:row inSection:section];
[_switchStateAtIndex setObject:boolNumber forKey:indexPath];
}
}
break;
//section 2 phones
case phoneSection:
{
for(NSInteger row=0; row<[_contact.phoneNumbers count];row++)
{
NSIndexPath* indexPath = [NSIndexPath indexPathForRow:row inSection:section];
[_switchStateAtIndex setObject:boolNumber forKey:indexPath];
}
}
break;
//more code ..
3# In Table View Datasource Delegate load the state of switch at indexpath and
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{ UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell"];
SwitchWithIndex* mySwitch = [[SwitchWithIndex alloc] init];
[mySwitch addTarget:self action:#selector(switchChanged:) forControlEvents:UIControlEventValueChanged];
NSNumber* switchStateNumber =[_switchStateAtIndex objectForKey:indexPath];
BOOL switchState = [switchStateNumber boolValue];
mySwitch.on = switchState;
mySwitch.indexPath = [[NSIndexPath alloc]init];
mySwitch.indexPath = indexPath;
cell.accessoryView = mySwitch;
//more code
and the following code to detect change on switch state.
- (void) switchChanged:(id)sender {
SwitchWithIndex* mySwitch = sender;
NSIndexPath* indexPath = mySwitch.indexPath;
NSLog(#"%#",indexPath);
NSNumber* switchStateBool = [NSNumber numberWithBool:mySwitch.on ? YES : NO];
[_switchStateAtIndex setObject:switchStateBool forKey:indexPath];
NSLog( #"The switch is %#", mySwitch.on ? #"ON" : #"OFF" );
}
4# And finally save selected field based on switch state
+(CNMutableContact*)newContactFrom:(CNContact*)contact withSwitchState:(NSMutableDictionary*)switchState
{
CNMutableContact* aContact = [[CNMutableContact alloc]init];
for (NSIndexPath* indexPath in switchState.keyEnumerator)
{
NSNumber* boolNumber = [switchState objectForKey:indexPath];
BOOL switchOn = [boolNumber boolValue];
switch (indexPath.section) {
case basicInfoSection://basic info section (name,company,department,title)
{
int row = 0;
if(indexPath.row==row)
{
if(switchOn)
{
aContact.givenName = contact.givenName;
aContact.middleName = contact.middleName;
aContact.familyName = contact.familyName;
}
}
if(![contact.organizationName isEqualToString:#""])
{row += 1;
if(indexPath.row==row)//company row
{
//store company
if(switchOn)
aContact.organizationName = contact.organizationName;
}
}
//more code
There may be other solution to solve this issue, above is what I can do for now.
Rather than enumerating all of the cells in a table view, you need to store the state of the switches somewhere other than in the table view's cells. I would imagine that this is already being done, otherwise the state of the switches would not be reliable/consistent just from scrolling the table view.
For instance, in your cellForRowAtIndexPath: method, you must tell the cell whether the switch should be displayed as on or off. You would do this by holding the state of your switches in an instance-level array. Here is one way to do that:
#interface YourClass ()
{
// Create an instance-level array to store switch values.
NSMutableArray *switchValues;
}
...
- (void)viewDidLoad {
switchValues = [NSMutableArray new];
for(int i = 0; i < YOUR_TABLE_SIZE; i++)
[switchValues insertObject:[NSNumber numberWithBool:DEFAULT_SWITCH_STATE]];
// Alternatively, populate your array with another data object if all the
// switches do not have the same default starting state (on/off).
}
...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
YourCustomCell *cell = [tableView dequeueReusableCellWithIdentifier:#"CellIdentifier" forIndexPath:indexPath];
...
// Add a target to the switch so we know when it toggles.
[cell.toggleSwitch addTarget:self action:#selector(switchSwitched:) forControlEvents:UIControlEventValueChanged];
cell.toggleSwitch.tag = indexPath.row;
// Set the state to the appropriate value.
cell.toggleSwitch.on = [[switchValues objectAtIndex:indexPath.row] boolValue];
return cell;
}
- (void)switchSwitched:(UISwitch *)switcher
{
// Toggle the switch's value in the instance array
[switchValues replaceObjectAtIndex:switcher.tag withObject:[NSNumber numberWithBool:switcher.on]];
}

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];
}

objective c ios checked more cell with one touch

I want checked more cell with one click(touch).
In this code I try to do what I said bat ... I have some problem
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *riga;
int esci=0;
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
NSDictionary *itemAtIndex = (NSDictionary *)[listad objectAtIndex:indexPath.row];
riga=[itemAtIndex objectForKey:#"riga"];
for (int i=0; i<[righeS count]; i++) {
if ([righeS objectAtIndex:i] ==riga) {
cell.accessoryType=UITableViewCellAccessoryNone;
//[tableView deselectRowAtIndexPath:indexPath animated:YES];
[righeS removeObjectAtIndex:i];
esci=1;
}
}
if (esci==0) {
[righeS addObject:riga];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
//Check if value of qty of the next row is 0
bool trovato=FALSE;
for (int g =0 ;g <[listad count];g++){
NSDictionary *rigaScan=(NSDictionary*)[listad objectAtIndex:g];
if (trovato==TRUE) {
if ([[rigaScan objectForKey:#"qty"] isEqualToString: #"0"]){
NSString *rig;
rig=[rigaScan objectForKey:#"riga"];
[righeS addObject:rig];
cell.accessoryType=UITableViewCellAccessoryCheckmark;
}else{
break;
}
}
if ([rigaScan objectForKey:#"riga"]==riga){
trovato=TRUE;
}
[rigaScan release];
}
//Fine controllo
}
}
In this event I try when the user touches a cell to see if some value of the next cell is 0.
If the value is 0, I have to check also the next cell and the other value in the for iterate.
When the next value is !=0 I put break.
I believe that the logical code is correct but maybe not the syntax for cocoa.
Try this wonderful post from Cocoa With Love - Multiple row selection and editing in a UITableView

Resources