Multiple Checkmark When Row Selected in Uitableview iOS

Selecting TableView Cell Activates Checkmark in Rows in Multiple Sections

use data store for save checkmarks like this:

var selectedIngredients: Set<IndexPath> = [] // use set for unique save

then didSelect callBack:

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){
if self.selectedIngredients.contains(indexPath) {
self.selectedIngredients.remove(indexPath)

} else {
self.selectedIngredients.insert(indexPath)
}

self.tableView.reloadData()
}

after reload in CellForRow:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if selectedIngredients.contains(indexPath) {
cell.accessoryType = .checkmark
} else {
cell.accessoryType = .none
}
}

If you want it to have only one Row contain checkmark:

var selectedIngredients: IndexPath? = nil

and didSelect CallBack:

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){
self.selectedIngredients = indexPath
}

and finally:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if selectedIngredients == indexPath {
cell.accessoryType = .checkmark
} else {
cell.accessoryType = .none
}
}

Multiple checkMark when row selected in UITableView IOS

[self.tableView cellForRowAtIndexPath:indexPath] call in the didSelectRowAtIndexPath will not return the exact cell. It can be same cell, new cell or reused cell. If it is a reused cell at its accessory view has a checkmark, you will end up having two cells with checkmark.

Its better to store in the array and use it accordingly. If you are planning to have multiple selections, Use the code example below.

- (void)viewDidLoad
{
[super viewDidLoad];

// Do any additional setup after loading the view, typically from a nib.
self.cellSelected = [NSMutableArray array];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//Cell Initialisation here

if ([self.cellSelected containsObject:indexPath])
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else
{
cell.accessoryType = UITableViewCellAccessoryNone;

}
return cell;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
//if you want only one cell to be selected use a local NSIndexPath property instead of array. and use the code below
//self.selectedIndexPath = indexPath;

//the below code will allow multiple selection
if ([self.cellSelected containsObject:indexPath])
{
[self.cellSelected removeObject:indexPath];
}
else
{
[self.cellSelected addObject:indexPath];
}
[tableView reloadData];
}

Add/Remove Multiple Checkmarks on Selected Rows in Swift 4 UITableView

Instead of change accessoryType on didSelectRowAt and didDeselectRowAt methods, you should override and do it on setSelected(_:animated:) from your cell class.

class YourCellClass: UITableViewCell {

override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)

if selected {
accessoryType = .checkmark
} else {
accessoryType = .none
}
}

}

UITableViewCell Checkmark Being Added to multiple rows when one is tapped

Maintain in your Data source which cell is to be selected.

Then in cellForRowAtIndexPath:

if (DropDownItems[indexPath.row].isSelected) {
cell.accessoryType = .Checkmark
} else {
cell.accessoryType = .None
}

and in your didSelectRowAtIndexPath Method:

if(DropDownItems[indexPath.row].isSelected) {
DropDownItems[indexPath.row].isSelected = false
} else {
DropDownItems[indexPath.row].isSelected = true
}

self.tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Fade)

how to make limited multiple checkmark in Table View Cell in Swift?

You can't simply add the checkmark to the cell; cell objects will be re-used as the tableview scrolls, so you will lose checkmarks and end up with checkmarks in cells that shouldn't have them.

You need to track the checked cells in another structure; I suggest using a Set<IndexPath>. You can either allow multi-selection in your tableview, or (my preference) deselect the row after you add the checkmark.

You also need to ensure that your cellForRowAt: sets the accessory type correctly

class CreateEventStep2VC: UIViewController {

@IBOutlet weak var eventTypeNameLabel: UILabel!
@IBOutlet weak var tableView: UITableView!

var newEvent : [String:Any]!
var eventTypeAvailableData = [String]()
var selectedEventTypes = Set<IndexPath>()

override func viewDidLoad() {
super.viewDidLoad()

// initial value
eventTypeNameLabel.text = ""

// get event Type Data list from EventType data model
eventTypeAvailableData = EventType.allValues.map { $0.toString() }
}

}

extension CreateEventStep2VC : UITableViewDataSource {

//MARK: - UITableViewDatasource

func numberOfSections(in tableView: UITableView) -> Int {
return 1
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return eventTypeAvailableData.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "EventTypeCell", for: indexPath) as! CreateEventStep2Cell
cell.eventTypeNames = eventTypeAvailableData[indexPath.row]
cell.accessoryType = selectedEventTypes.contains(indexPath) ? .checkMark:.none

return cell
}

}

extension CreateEventStep2VC : UITableViewDelegate {

//MARK: - UITableViewDelegate
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: false)
if selectedEventTypes.contains(indexPath) {
selectedEventTypes.remove(indexPath)
} else if selectedEventTypes.count < 3 {
selectedEventTypes.insert(indexPath)
}
tableView.reloadRows(at: [indexPath], animated:.none)
}
}

Swift - Multiple TableView checkmark - save and load choice

Don't use multiple arrays as data source. That's pretty bad practice and inefficient.

Delete them

var selectedCells = [IndexPath]()
var selectedAreas = [String]()

Declare Area as struct and add an isSelected member

struct Area {
let name : String
var isSelected : Bool

init(name : String, isSelected : Bool = false) {
self.name = name
self.isSelected = isSelected
}
}

var areas = [Area(name: "Foo"), Area(name: "Bar")]

In cellForRowAt assign the checkmark depending on isSelected

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
let area = areas[indexPath.row]
cell.textLabel?.text = area.name
cell.accessoryType = area.isSelected ? .checkmark : .none
return cell
}

In didSelectRow toggle isSelected and reload the row (yes, only two lines of code)

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
areas[indexPath.row].isSelected.toggle()
tableView.reloadRows(at: [indexPath], with: .none)
}

You get the selected areas with

let selectedAreas = areas.filter{$0.isSelected}

and an array of the names

let selectedAreaNames = areas.filter{$0.isSelected}.map{$0.name}

To load and save the names to UserDefaults add these two methods

func saveSelection()
{
let selectedAreaNames = areas.filter{$0.isSelected}.map{$0.name}
UserDefaults.standard.set(selectedAreaNames, forKey: "selectedNames")
}

func loadSelection()
{
guard let selectedAreaNames = UserDefaults.standard.array(forKey: "selectedNames") as? [String] else { return }
for (index, area) in areas.enumerated() {
areas[index].isSelected = selectedAreaNames.contains(area.name)
}
tableView.reloadData()
}

Swift: Multiple TableView checkmark - select all rows

You have to check if the user selected the first row ("Select all") and update the other rows accordingly:

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// toggle the selected area
areas[indexPath.row].isSelected.toggle()

// save the new state for later use
let isSelected = areas[indexPath.row].isSelected

if indexPath.row == 0 {
// "Select all" was selected – update all areas
for i in 1..<areas.count {
areas[i].isSelected = isSelected
}

// update UI
tableView.visibleCells.forEach { $0.accessoryType = isSelected ? .checkmark : .none }
} else {
// update UI
tableView.cellForRow(at: indexPath)?.accessoryType = isSelected ? .checkmark : .none
}

tableView.deselectRow(at: indexPath, animated: true)
}

Recommendation

To separate concerns visually you could also use an own table view section for the "Select all" row. In that case some more changes are necessary:

var areas = [
// you do not need an area for "Select all" any longer
Area(name: "a"),
Area(name: "b"),
Area(name: "c"),
Area(name: "d")
]

var allSelected: Bool {
// helper var to see if all areas are currently selected
return areas.filter({!$0.isSelected}).isEmpty
}

override func numberOfSections(in tableView: UITableView) -> Int {
return 2
}

override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
switch section {
case 1: return "Areas"
default: return nil
}
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
switch section {
case 0: return 1 // select all
case 1: return areas.count
default:
// we should never get here
fatalError()
}
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.selectionStyle = .none

if indexPath.section == 0 {
cell.textLabel?.text = "Select all"
cell.accessoryType = allSelected ? .checkmark : .none
} else {
let area = areas[indexPath.row]
cell.textLabel?.text = area.name
cell.accessoryType = area.isSelected ? .checkmark : .none
}

return cell
}

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.section == 0 {
// (de-)select all
let shouldSelect = !allSelected
for i in 0..<areas.count {
areas[i].isSelected = shouldSelect
}
} else {
areas[indexPath.row].isSelected.toggle()
}

tableView.reloadRows(at: tableView.indexPathsForVisibleRows ?? [], with: .automatic)
}

When i scrolling on UITableview,the checkmark of multiple selected rows are disappears.how to solve this?

The problem lies in this piece of code:

if([_selectedstatearray containsObject:indexPath]) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else {
cell.accessoryType = UITableViewCellAccessoryNone;
}

You are checking if _selectedstatearray contains the specified indexPath while you store them as NSString [_selectedstatearray addObject:cellText];

Replace the code above with this:

NSString *text = [statearray objectAtIndex:indexPath.row];
if([_selectedstatearray containsObject:text]) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else {
cell.accessoryType = UITableViewCellAccessoryNone;
}


Related Topics



Leave a reply



Submit