How to remove the check mark on another click? - ios

I want to make a table that user can select and deselect with a check mark:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *) indexPath
{
...;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
- (void)tableView:(UITableView *) tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
...;
newCell.accessoryType = UITableViewCellAccessoryCheckmark;
...;
}
I was trying to remove the check mark when clicking on the check-marked cell again, but it takes 2 clicks to do that instead of one.
If I set selection style to default, when I click on a selected row, it removes the blue highlight; clicking again, it removes the check mark.
I also tried some conditional statements in didSelectRowAtIndexPath, but they only respond to second click as well.
What causes the problem and how do I fix it?

You can try this one:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSUInteger index = [[tableView indexPathsForVisibleRows] indexOfObject:indexPath];
if (index != NSNotFound) {
UITableViewCell *cell = [[tableView visibleCells] objectAtIndex:index];
if ([cell accessoryType] == UITableViewCellAccessoryNone) {
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
} else {
[cell setAccessoryType:UITableViewCellAccessoryNone];
}
}
}
This should toggle the cell's checkmark on every touch.
If you additionally want only one cell to appear selected at a time, also add the following:
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath {
NSUInteger index = [[tableView indexPathsForVisibleRows] indexOfObject:indexPath];
if (index != NSNotFound) {
UITableViewCell *cell = [[tableView visibleCells] objectAtIndex:index];
[cell setAccessoryType:UITableViewCellAccessoryNone];
}
}
If you don't want the blue hilight background, simply set the cell's selection style to UITableViewCellSelectionStyleNone once you create the cell.

Based on Starter's link to Apple docs (my code in Swift 3):
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
if let cell = tableView.cellForRow(at: selectedIndexPath) {
cell.accessoryType = .none
}
if let cell = tableView.cellForRow(at: indexPath) {
cell.accessoryType = .checkmark
}
selectedIndexPath = indexPath
}
The main point is to keep track of currently selected cell and change cell.accessoryType accordingly. Also don't forget to properly set cell.accessoryType in tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) based on selectedIndexPath.

Check this Apple official doc
best solution ever

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (index != NSNotFound) {
UITableViewCell *cell = [[tableView visibleCells] objectAtIndex:index];
if (cell.accessoryType == UITableViewCellAccessoryNone)
cell.accessoryType = UITableViewCellAccessoryCheckmark;
else
cell.accessoryType = UITableViewCellAccessoryNone;
[self.tableName reloadData];
}
}
This helps in toggling the checkmarks (remove the check mark when clicking on the check-marked cell again)

You can use this:
You can use this:
if tableView.cellForRow(at: indexPath)?.accessoryType == .checkmark { tableView.cellForRow(at: indexPath)?.accessoryType = .none } else { tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark } tableView.deselectRow(at: indexPath, animated: true)

Related

How to get multiple selected row value from uitableview and save multiple selected value in array? [duplicate]

This question already has answers here:
Select multiple rows in UITableview [duplicate]
(5 answers)
Closed 6 years ago.
I have list of states in UITableView.Now i want to select multiple row of UITableView and wanna get this selected row values in one array.how can i get this?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//NSMutableArray *arrData =[statearray objectAtIndex:indexPath.row];
NSLog(#"arrdata>>%#",statearray);
static NSString *simpleTableIdentifier = #"SimpleTableItem";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
cell.textLabel.text = [statearray objectAtIndex:indexPath.row];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView cellForRowAtIndexPath:indexPath].accessoryType = UITableViewCellAccessoryCheckmark;
}
You can call tableview.indexPathForSelectedRows. This will output an array with the indexpaths for all selected rows in your tableview!
This is how your code would look like in swift 3:
var values : [String] = []
let selected_indexPaths = tableView.indexPathsForSelectedRows
for indexPath in selected_indexPaths! {
let cell = tableView.cellForRow(at: indexPath)
values.append((cell?.textLabel?.text)!)
}
After running this code the values of all selected cells should be in the values array.
you can keep track of selected cells with below way
var selectedCells: [UITableViewCell] = []
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
selectedCells.append(tableView.cellForRow(at: indexPath)!)
}
override func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
let deselectedRow = tableView.cellForRow(at: indexPath)
if(selectedCells.contains(deselectedRow!)){
let indx = selectedCells.index(of: deselectedRow!)
selectedCells.remove(at: indx!)
}
}
Idea is to maintain array of selected cells when cell selection happens and remove cell once deselection is done
Best way is to get selected indexpaths using method
tableView.indexPathsForSelectedRows
you can get the data out in an array
var oldArray: [NSIndexPath] = [NSIndexPath.init(row: 0, section: 0), NSIndexPath.init(row: 1, section: 0), NSIndexPath.init(row: 2, section: 0), NSIndexPath.init(row: 3, section: 0)]
var newArray: [Int] = oldArray.flatMap { ($0.row) }
Like if we have array in form of oldArray, We can get only rows using flatMap.
There is default method of tableview,
self.tableView.indexPathsForSelectedRows
Which gives you an array of selected indexpaths. But you need to also set property of tableview
self.tableView.allowsMultipleSelection = true
If want back selcted rows to track,
NSArray *selectedRowsArray = [yourTableViewName indexPathsForSelectedRows];
Answer updated
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
//the below code will allow multiple selection
if ([yourMutableArray containsObject:indexPath])
{
[yourMutableArray removeObject:indexPath];
}
else
{
[yourMutableArray addObject:indexPath];
}
[yourTableView reloadData];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *simpleTableIdentifier = #"SimpleTableItem";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
if ([yourMutableArray containsObject:indexPath])
{
//Do here what you wants
if (contentArray.count > 0) {
NSDictionary *dictObje = [contentArray objectAtIndex:indexPath.row];
cell.textLabel.text = [NSString stringWithFormat:#"%#",[dictObje objectForKey:#"name"]];
}
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else
{
//Do here what you wants
if (contentArray.count > 0) {
NSDictionary *dictObje = [contentArray objectAtIndex:indexPath.row];
cell.textLabel.text = [NSString stringWithFormat:#"%#",[dictObje objectForKey:#"name"]];
}
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}

Get checkbox on tableview cell [duplicate]

This question already has answers here:
UITableView Multiple Selection
(11 answers)
Closed 6 years ago.
I know this question has been asked before, but there is a confusion among those. As i need multiple checkmark on cell and on clicking again on that cell checkmark should be set to none for that selected cell. i have tried this but all cell get selected doesnot none when again clicking on selected cell. i have tried this.
- (UITableViewCell )tableView:(UITableView )tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
myTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"myTableViewCell" forIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryNone;
return cell;
}
and in didSelectRowAtIndexPath
- (void)tableView:(UITableView )tableView didSelectRowAtIndexPath:(NSIndexPath )indexPath
{
myTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"myTableViewCell" forIndexPath:indexPath];
if ( cell.accessoryType == UITableViewCellAccessoryNone) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
}
and in didDeselectRowAtIndexPath
-(void)tableView:(UITableView )tableView didDeselectRowAtIndexPath:(NSIndexPath )indexPath
{
myTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"myTableViewCell" forIndexPath:indexPath];
if ( cell.accessoryType == UITableViewCellAccessoryNone) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
}
Please help.
You just need to maintain the state of cell whether is it selected or not.
Try this in your cellForRowAtIndexPath.
if ([tableView.indexPathsForSelectedRows containsObject:indexPath]) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else
{
cell.accessoryType = UITableViewCellAccessoryNone;
}

How to select multiple rows in UITableView in edit mode?

I want to ask, how can I forward to edit mode, where I can to select multiple rows, as in Messages app, when you click on top right button "Select", when you can choose multiple messages by tapping on circles.
Like this:
I searched a lot, really, but couldn't find anything. Can anyone help me? Some advices
Set
tableView.allowsMultipleSelectionDuringEditing = true
Screenshot
Demo code
class TableviewController:UITableViewController{
override func viewDidLoad() {
super.viewDidLoad()
tableView.allowsMultipleSelectionDuringEditing = true
tableView.setEditing(true, animated: false)
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath)
cell.textLabel?.text = "\(indexPath.row)"
return cell
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
}
If you're using Storyboards do this:
NSMutableArray *selected;
decleare it in you viewcontroller.h file..
selected =[[NSMutableArray alloc]init];
for (int i=0; i<[YOUR_ARRAY count]; i++) // Number of Rows count
{
[selected addObject:#"NO"];
}
add same number of "NO" in selected array using above code for that you had to replace YOUR_ARRAY with your data array that you show in table.
if(![[selected objectAtIndex:indexPath.row] isEqualToString:#"NO"])
{
cell.accessoryType=UITableViewCellAccessoryCheckmark;
}
else
{
cell.accessoryType=UITableViewCellAccessoryNone;
}
put above code in your -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)path {
UITableViewCell *cell = [tableView cellForRowAtIndexPath:path];
if (cell.accessoryType == UITableViewCellAccessoryNone) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
[selected replaceObjectAtIndex:path.row withObject:#"YES"];
} else {
cell.accessoryType = UITableViewCellAccessoryNone;
[selected replaceObjectAtIndex:path.row withObject:#"NO"];
}
}
also put this to work correctly..

How can I get the class (custom) of cell selected in UITableView?

Usually I get my selected cell this way:
- (void)tableView:(UITableView *)table didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
CustomCell *cell = (CustomCell*) [table cellForRowAtIndexPath:indexPath];
}
But in the code I'm working with, I may have many kind of cells in my table view. How can I get the class of my selected cell (if it's for example CustomCell or CustomCell2) ?
You can check the type of cell returned
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if ([cell isKindOfClass:[CustomCell class]]) {
//do specific code
}else if([cell isKindOfClass:[CustomCell2 class]]){
//Another custom cell
}else{
//General cell
}
SWIFT 4
Just in case, if someone needed it. Get the instance of selected cell and then check it for required tableViewCell type.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
guard let cell = myCustomCell.cellForRow(at: indexPath)
else
{
return
}
/** MyCustomCell is your tableViewCell class for which you want to check. **/
if cell.isKind(of: MyCustomCell.self)
{
/** Do your stuff here **/
}
}

How to let user to modify the text in UITableView cells

I have a question regarding uitable view.
I am implementing an app which is similar to the address book app.I am able to present the table view in editing mode. I want to let the user to edit the text in the cells in editing mode. I know that in order to edit the text in the cells, I need a textfield. I have created a textfield.
My question is:
what should I do in order to present that textfield in the cells.
what are the methods I need to implement in order to present that text field in the table view in editing mode.
Once I am done with editing ,How can I update the data which is in my contacts view controller(contains all the contacts).The saving should persist in the address book. For this question I know that I need to implement some delegate method,But I am not sure how to do that.
Please have a look at the following code,so that you will have an idea about my problem.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath
{
[tableView setSeparatorColor:[UIColor clearColor]];
//[self.tableView setEditing: YES animated: YES];
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell"];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
// Configure the cell...
if(isEditingOn) {
if(cell == nil)
cell = [self getCellContentView:CellIdentifier];
UILabel *lblTemp1 = (UILabel *)[cell viewWithTag:1];
UITextField *textfield1=(UITextField*)[cell viewWithTag:2];
if(indexPath.row == 0) {
lblTemp1.text = #"Name";
textfield1.text = myContact.name;
}
else if(indexPath.row == 1) {
lblTemp1.text = #"Phone";
textfield1.text = myContact.phone;
}
else if(indexPath.row == 2) {
lblTemp1.text = #"Email";
textfield1.text = myContact.email;
}
}
else {
if(indexPath.row == 0) {
cell.textLabel.text = myContact.name;
}
else if(indexPath.row == 1) {
cell.textLabel.text = myContact.phone;
}
else if(indexPath.row == 2) {
cell.textLabel.text = myContact.email;
}
}
return cell;
}
- (UITableViewCell *) getCellContentView:(NSString *)cellIdentifier {
CGRect CellFrame = CGRectMake(0, 0, 60, 20);
CGRect Label1Frame = CGRectMake(10, 10, 180, 25);
UILabel *lblTemp;
UITableViewCell *cell = [[[UITableViewCell alloc] initWithFrame:CellFrame reuseIdentifier:cellIdentifier] autorelease];
lblTemp = [[UILabel alloc] initWithFrame:Label1Frame];
lblTemp.tag = 1;
[cell.contentView addSubview:lblTemp];
[lblTemp release];
CGRect TextFieldFrame=CGRectMake(240, 10, 60, 25);
UITextField *textfield;
textfield=[[UITextField alloc]initWithFrame:TextFieldFrame];
textfield.tag=2;
textfield.placeholder = #"";
[cell.contentView addSubview:textfield];
}
This is a really complex question to answer this fully and in-depth with code examples, but I'll try to point you in the right direction.
1) Add a UITextField as a subview of your table cell when you create the cell in the tableView:cellForRowAtIndexPath: method (I assume that's what your getCellContentView: method is for). Set a tag on your UITextField that matches the row index of the cell and make your tableviewcontroller the delegate for the cell. Set the textfield to hidden. (remember to set the tag each time the cell is requested, not just the first time you create it).
2) In the tableView:didSelectRowAtIndexPath: method, grab the cell using tableViewCellForRowAtIndexPath and then show the textfield inside it (you may have to do some view traversal to get it) and call becomeFirstResponder on the textfield.
3) When the user has typed something, your textfielddelegate methods will be fired. You can look at the tag on the textfield to work out which row the field belongs to and then update the dat source with the new text. Then just reload the table to hide the textfield and update the cell content.
If you know how to use custom table cell subclasses then you can make your life a bit easier by creating a custom cell that already contains a textfield and has an property for accessing it, but otherwise the technique will be mostly the same.
Also, tableView:didSelectRowAtIndexPath: won't normally fire when a tableview is in edit mode unless you set tableView.allowsSelectionDuringEditing = YES;
It's better to use 2 UITableViewCells, The first one for view and the last for edit mode.
Also we will depend on the variable rowToEdit which refers to the current editing row. (in my case one cell is allowed to be edited at the same time)
let us begin:
First I depend on accessoryButtonTap action to edit the row:
var rowToEdit: IndexPath? = nil
override func tableView(_ tableView: UITableView, accessoryButtonTappedForRowWith indexPath: IndexPath) {
// End edit mode if one cell being in edit mode other than this one
if let row = self.rowToEdit {
// return current edit cell to view mode
self.rowToEdit = nil
self.tableView.reloadRows(at: [row], with: .automatic)
}
self.rowToEdit = indexPath
self.tableView.reloadRows(at: [self.rowToEdit!], with: .automatic)
}
Differentiate between the 2 modes when you will load the cell:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath == self.rowToEdit {
let cellId = "ContactEditTableViewCell"
let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath as IndexPath) as! ContactEditTableViewCell
cell.accessoryType = .none
self.configEditCell(cell: cell, indexPath: indexPath)
return cell
} else {
let cellId = "ContactTableViewCell"
let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath as IndexPath) as! ContactTableViewCell
self.configCell(cell: cell, indexPath: indexPath)
return cell
}
}
Additional option if you want to change the height based on mode:
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath == self.rowToEdit {
return 120
} else {
return 70
}
}
Last option to add Save and Cancel buttons:
I added them to each cell, So I pass a reference to the ContactTable to each cell.
#IBAction func btnSave_click(_ sender: UIButton) {
// save the record
btnCancel_click(sender)
}
#IBAction func btnCancel_click(_ sender: UIButton) {
let tmp = self.tbl.rowToEdit
self.tbl.rowToEdit = nil
self.tbl.tableView.reloadRows(at: [tmp!], with: .automatic)
}

Resources