Single cell Selection in table view in swift
Solution 1
You have to save selected indexes somewhere, may be in some array with different sections. Since you want to have first cells of each section pre-selected lets start with something like this:
var selectedIndexes = [[IndexPath.init(row: 0, section: 0)], [IndexPath.init(row: 0, section: 1)]]
In above array we are saving two indexpaths. One is for first cell of first section and the second is for first cell of second section.
Now your cellForRow may check for existing indexpaths in the array like so:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: CellIdentifier) as! UITableViewCell
cell.selectionStyle = .none
cell.textLabel?.text = tableArray[indexPath.section][indexPath.row]
let selectedSectionIndexes = self.selectedIndexes[indexPath.section]
if selectedSectionIndexes.contains(indexPath) {
cell.accessoryType = .checkmark
}
else {
cell.accessoryType = .none
}
return cell
}
For single selection:
// For single selection
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath)
// If current cell is not present in selectedIndexes
if !self.selectedIndexes[indexPath.section].contains(indexPath) {
// mark it checked
cell?.accessoryType = .checkmark
// Remove any previous selected indexpath
self.selectedIndexes[indexPath.section].removeAll()
// add currently selected indexpath
self.selectedIndexes[indexPath.section].append(indexPath)
tableView.reloadData()
}
}
Above code removes any previously selected cell and saves the new one. If the same cell is selected again and again it remains checked.
Solution 2
You can try following method to keep one cell selected at one time
**My arrays**
let section = ["pizza", "deep dish pizza", "calzone"]
let items = [["Margarita", "BBQ Chicken", "Peproni", "BBQ Chicken", "Peproni"], ["sausage", "meat lovers", "veggie lovers"], ["sausage", "chicken pesto", "prawns & mashrooms"]]
/// Lets keep index Reference for which cell is
/// Getting selected
var selectedIndex : [Int:Int]?
/// Now in didLoad
override func viewDidLoad() {
super.viewDidLoad()
/// Initialise the Dictionary
selectedIndex = [Int:Int]()
/// Set the Default value as in your case
/// Section - 0 and IndexPath - 0
/// i.e First cell
selectedIndex?.updateValue(0, forKey: 0)
mainTableView.delegate = self
mainTableView.dataSource = self
mainTableView.reloadData()
}
func numberOfSections(in tableView: UITableView) -> Int {
return section.count
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 40
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
/// my Header cell
let headerCell = tableView.dequeueReusableCell(withIdentifier: "HeaderCell") as! TableViewCell
headerCell.titleLabel.text = self.section[section]
headerCell.ButtonToShowHide.tag = section
return headerCell.contentView
}
/// Now in CellForRowMethod
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
cell.textLabel?.text = items[indexPath.section][indexPath.row]
/// Compare if current section is Available in reference Dict
if let val = selectedIndex![indexPath.section]{
/// If Yes
/// Check IndexPath Row Value
if indexPath.row == val{
/// If row is found that is selected
/// Make it highlight
/// You can set A radio button
cell.textLabel?.textColor = UIColor.red
}
else{
/// Set default value for that section
cell.textLabel?.textColor = UIColor.black
}
}
/// If no
else{
/// Required to set Default value for all other section
/// And
/// Required to Update previous value if indexPath was selected
/// In previouus index Section
cell.textLabel?.textColor = UIColor.black
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
/// Remove All values
selectedIndex?.removeAll()
/// Insert current Value
selectedIndex?.updateValue(indexPath.row, forKey: indexPath.section)
/// Reload TableView Fully
/// Or you can keep Reference of Previous and New Value
/// For not reloading All cells
self.mainTableView.reloadData()
}
Output
when TableView is Loaded
When row selected in same section
when row selected in other section
GIF Working - Updating Cell Label Color
Re-Upddate
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
cell.textLabel?.text = items[indexPath.section][indexPath.row]
/// Compare if current section is Available in reference Dict
if let val = selectedIndex![indexPath.section]{
/// If Yes
/// Check IndexPath Row Value
if indexPath.row == val{
/// If row is found that is selected
/// Make it highlight
/// You can set A radio button
cell.accessoryType = .checkmark
}
else{
/// Set default value for that section
cell.accessoryType = .none
}
}
/// If no
else{
/// Required to set Default value for all other section
/// And
/// Required to Update previous value if indexPath was selected
/// In previouus index Section
cell.accessoryType = .none
}
return cell
}
Solution 3
- Enable
allowsMultipleSelection
to select multiple cell at a time. -
Use tableView(_:willSelectRowAt:) to handle selection. If there is a selected cell in |indexPath.section|, deselect this row
func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? { let indexPathsForSelectedRows = tableView.indexPathsForSelectedRows ?? [IndexPath]() // If there is a selected cell in |indexPath.section|, do nothing for selectedIndexPath in indexPathsForSelectedRows { if selectedIndexPath.section == indexPath.section { tableView.deselectRow(at: selectedIndexPath, animated: true) } } return indexPath; }
raheem
Updated on December 05, 2022Comments
-
raheem over 1 year
i have a table view in which i have two sections. Both sections contain 3 cells under it. Now when i select any cell it shows tick sign, but it selects one cell from both section. i have tried some code but it isn't working. I want that user can select a single cell from both sections and when the table view load its first cell should be preselected. How can i do that? i'm bit confused about preselection of cell.My code for cell selection is this,
self.filterTableView.allowsSelection = true extension FiltersVC: UITableViewDelegate,UITableViewDataSource{ func numberOfSections(in tableView: UITableView) -> Int { return 2 } func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { return sectionTitles[section] } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return menuItems[section].count } func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { return 60 } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = filterTableView.dequeueReusableCell(withIdentifier: "filterCell", for: indexPath) as! FiltersTableViewCell cell.tilteLbl.text = menuItems[indexPath.section][indexPath.row] cell.selectionStyle = UITableViewCellSelectionStyle.none cell.accessoryType = cell.isSelected ? .checkmark : .none cell.selectionStyle = .none cell.backgroundColor = UIColor.clear return cell } func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { return 30 } func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { let headerView = UIView() headerView.backgroundColor = #colorLiteral(red: 0.9130856497, green: 0.9221261017, blue: 0.9221261017, alpha: 1) let headerText = UILabel() headerText.textColor = UIColor.black headerText.adjustsFontSizeToFitWidth = true switch section{ case 0: headerText.textAlignment = .center headerText.text = "LIST BY" headerText.backgroundColor = #colorLiteral(red: 0.9190355449, green: 0.9281349067, blue: 0.9281349067, alpha: 1) headerText.font = UIFont.boldSystemFont(ofSize: 20) case 1: headerText.textAlignment = .center headerText.text = "COUSINE" headerText.backgroundColor = #colorLiteral(red: 0.921431005, green: 0.9214526415, blue: 0.9214410186, alpha: 1) headerText.font = UIFont.boldSystemFont(ofSize: 20) default: break } return headerText } func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { if indexPath.section == 0 { if let cell = filterTableView.cellForRow(at: indexPath) { cell.accessoryType = .checkmark let item = menuItems[indexPath.section][indexPath.row] UserDefaults.standard.set(item, forKey: "listBy") UserDefaults.standard.synchronize() filterBtn.isUserInteractionEnabled = true filterBtn.backgroundColor = #colorLiteral(red: 0.9529120326, green: 0.3879342079, blue: 0.09117665142, alpha: 1) } } else if indexPath.section == 1{ if let cell = filterTableView.cellForRow(at: indexPath) { cell.accessoryType = .checkmark let item = menuItems[indexPath.section][indexPath.row] UserDefaults.standard.set(item, forKey: "Cuisine") UserDefaults.standard.synchronize() filterBtn.isUserInteractionEnabled = true filterBtn.backgroundColor = #colorLiteral(red: 0.9529120326, green: 0.3879342079, blue: 0.09117665142, alpha: 1) } } } func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) { if indexPath.section == 0 { if let cell = filterTableView.cellForRow(at: indexPath as IndexPath) { cell.accessoryType = .none } } else if indexPath.section == 1{ if let cell = filterTableView.cellForRow(at: indexPath as IndexPath) { cell.accessoryType = .none } } }
-
trungduc almost 6 yearsCan you explain your problem again? As I understand, when you select a cell, tick sign is displayed on 2 cell and now you want to select only one cell each at a time. Is it right?
-
raheem almost 6 yearsProblem is that , i have a table view in that i have two sections and under each section there are three cells. When i select any cell from section 0 it deselect the cell selected from section 1 and when i select any cell from section 1 it deselect cell from section 0 . @trungduc
-
raheem almost 6 yearshave u got it? @trungduc
-
trungduc almost 6 yearsYes, you can try to add this line
self.filterTableView.allowsMultipleSelection = true
. And check this answer for right way to handle check marks stackoverflow.com/questions/50112804/… -
raheem almost 6 yearsi have tried this from this it allows multiple selections of cell from each section but i want single cell selection from each section. @trungduc
-
-
raheem almost 6 yearsi have two sections in my table view section at 0 index and section at 1 index. @iOS Geek
-
iOS Geek almost 6 yearsI used three sections
-
iOS Geek almost 6 yearsI updated Screenshots that may make you clear about my sections and its cells inside, You just need to copy my cellForRow Comparison code and didSelect Code for updating dictionary used here for reference selected index, this will basically let you select only one cell at one time from any of your section, I just changed textColor there you need to modify your check box
-
raheem almost 6 yearsthere is no selected cell in your screenshots. @iOS Geek
-
iOS Geek almost 6 yearsI modified text color one in red is selected others are black means unselected , check my cellforRow code I just updated cell.textLabel?.textColor in place of this you need to set your checkBox
-
iOS Geek almost 6 yearsplease Check I just added a GIF that shows live working
-
raheem almost 6 yearsBro i'm using simple checkmark in table view can show how it can be use in ur code? @iOS Geek
-
iOS Geek almost 6 yearsplease check I updated cellForRow Code all other didSelect and DIdLoad code is to be used same as I did
-
raheem almost 6 yearsaccording to gif u r selecting single cell from whole table view but i want single cell from single section. @iOS Geek
-
raheem almost 6 yearshow it differentiate in sections? @trungduc
-
iOS Geek almost 6 yearsin my tableView I have used 3 sections check my sectionArray and in Number OfSections I did returned section array count and in didSelect I am maintaining a dictionary with reference of selectedSection and selected Cell index
-
iOS Geek almost 6 yearsmy Section Array ["pizza", "deep dish pizza", "calzone"] my sectionCode is in ViewForHeaderInSection
-
raheem almost 6 yearsBro your code preselect the cell perfectly but when i tried to select any other cell it does not deselect the previous one. @HAK
-
HAK almost 6 yearsIts working fine for me. Make sure you are not doing anything in your didDeselect method. Just comment it out to check.
-
HAK almost 6 yearsAlso make sure tableView's selection property is set to single selction.
-
raheem almost 6 yearsi have written in viewDidLoad , tableview.allowSelection = true. but its selecting more than one cell. @HAK
-
raheem almost 6 yearslet me try. @trungduc
-
HAK almost 6 yearsHere, we are not using tableview's own selection functionality. We are storing the indexes by ourselves instead and adding and removing checkmarks manually after checking the indexes.
-
HAK almost 6 years@raheem add these two lines in your viewDidLoad method: tableView.allowsSelection = true tableView.allowsMultipleSelection = false
-
raheem almost 6 yearsso how can it make single selection . @HAK
-
HAK almost 6 yearsWhen it draws a cell in cellForRow, it checks for the indexpath of the cell to be contained in selectedIndexes array. If it is there, it adds a checkmark. If not it removes it. Similarly when you select a cell, didSelect is called which checks if the current index is in the array, if it finds it, it removes it and removes the checkmark from the cell. Otherwise if index is not present it adds the index in the selectedIndexes array and adds the checkmark to the cell.
-
raheem almost 6 yearsbro still its selecting multiple cells :( . @HAK
-
HAK almost 6 yearsYou want one cell to be selected from a single section? And preselection is removed once second cell is selected from the section?
-
raheem almost 6 yearsgetting this error. Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value in for loop. @trungduc
-
raheem almost 6 yearsyes thats what i want and also i want the selected cell name also. @HAK
-
HAK almost 6 years@raheem Edited!
-
raheem almost 6 yearslet me try. @trungduc
-
raheem almost 6 yearsyup got it, how can i get the name of labels that are selected? @HAK
-
HAK almost 6 yearsUsing the indexpaths selected. e.g: let label = array[indexpath.section][indexpath.row]. It mainly depends upon your datastructure that you are using.
-
raheem almost 6 yearsi have to give section number static to get indivisual names? @HAK
-
HAK almost 6 yearsJust as you are setting the text in your cellForRow method you can access the cell name in didSelectRow method like let name = menuItems[indexPath.section][indexPath.row]
-
raheem almost 6 yearshow can i get the name through section wise? @HAK
-
HAK almost 6 yearsLet us continue this discussion in chat.
-
trungduc almost 6 years@HAK why do we need another array to keep selected indexes while
UITableView
hasindexPathsForSelectedRows
property? developer.apple.com/documentation/uikit/uitableview/…