I'm working on a tableview
I want to be able to tap on each cell and when tapped, it displays a checkmark on the cell
Now I have some code that makes this work:
// checkmarks when tapped
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let section = indexPath.section
let numberOfRows = tableView.numberOfRowsInSection(section)
for row in 0..<numberOfRows {
if let cell = tableView.cellForRowAtIndexPath(NSIndexPath(forRow: row, inSection: section)) {
cell.accessoryType = row == indexPath.row ? .Checkmark : .None
}
}
}
but this code only selects 1 cell inside a section (I have 5 sections)
I need it to select any cell anywhere
Also when I drag my screen up and down I lose by checkmark
viewcontroller.swift
class ViewController: UIViewController, UITableViewDataSource { //class and subclass |)
//---------------------------------------------------------------------------------------------------------------------------/
// Variable and constant, also IBAOutlet
let section1 =
["this is used",
"this is used to test",
"this is used to test the lenght",
"this is used to test the lenght of the text",
"this is used to test the lenght of the text",
"this is used to test the lenght of the text",
"this is used to test the lenght of the text",
"this is used to test the lenght of the text",
"this is used to test the lenght of the text",]
let section2 =
["this is used to test the lenght of the text"]
let section3 =
["this is",
"this is ",]
#IBOutlet weak var scoreshow: UILabel!
#IBOutlet weak var reset: UIButton!
#IBOutlet weak var tableView: UITableView!
// --------------------------------------------------------------------------------------
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
//----------------------------------------------------------------------------------------
// checkmarks when tapped
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{
if let cell = tableView.cellForRowAtIndexPath(indexPath) {
if cell.accessoryType == .Checkmark
{
cell.accessoryType = .None
}
else
{
cell.accessoryType = .Checkmark
}
}
}
//----------------------------------------------------------------------------------------
//number of sections for the table
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 5
}
//----------------------------------------------------------------------------------------
//Calculate the amount of rows
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return self.section1.count;
}
//----------------------------------------------------------------------------------------
//Cells text label and config
func tableView(tableView: UITableView,cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell:UITableViewCell = UITableViewCell(style:UITableViewCellStyle.Default, reuseIdentifier:"cell")
cell.textLabel!.text = section1[indexPath.row]
cell.textLabel!.numberOfLines = 0
return cell
}
//----------------------------------------------------------------------------------------
#IBAction func resetswitch(sender: UIButton) {
}
//----------------------------------------------------------------------------------------
}
Swift > 3.0
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
if let cell = tableView.cellForRow(at: indexPath) {
cell.accessoryType = .none
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let cell = tableView.cellForRow(at: indexPath) {
cell.accessoryType = .checkmark
}
}
I solved by using two Swift functions: the didSelectRowAtIndexPath and the didDeselectRowAtIndexPath.
override func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
if let cell = tableView.cellForRowAtIndexPath(indexPath) {
cell.accessoryType = .None
}
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if let cell = tableView.cellForRowAtIndexPath(indexPath) {
cell.accessoryType = .Checkmark
}
}
To make this work properly, add a line of code to your cellForRowAtIndexPath function to select a row when the table view is drawn on the screen, otherwise the didDeselectRowAtIndexPath will not be called the first time you select another row. Like so:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cellData", forIndexPath: indexPath)
if (some condition to initially checkmark a row)
cell.accessoryType = .Checkmark
tableView.selectRowAtIndexPath(indexPath, animated: false, scrollPosition: UITableViewScrollPosition.Bottom)
} else {
cell.accessoryType = .None
}
return cell
}
Try this:
var checked = [Bool]() // Have an array equal to the number of cells in your table
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCellWithIdentifier("cell") as! UITableViewCell
//configure you cell here.
if !checked[indexPath.row] {
cell.accessoryType = .None
} else if checked[indexPath.row] {
cell.accessoryType = .Checkmark
}
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if let cell = tableView.cellForRowAtIndexPath(indexPath) {
if cell.accessoryType == .Checkmark {
cell.accessoryType = .None
checked[indexPath.row] = false
} else {
cell.accessoryType = .Checkmark
checked[indexPath.row] = true
}
}
}
To reset all the checkboxes:
func resetChecks() {
for i in 0.. < tableView.numberOfSections {
for j in 0.. < tableView.numberOfRowsInSection(i) {
if let cell = tableView.cellForRowAtIndexPath(NSIndexPath(forRow: j, inSection: i)) {
cell.accessoryType = .None
}
}
}
}
A UITableView keeps selected state for single or multiple selections. So IMO there would need to be a very good reason for keeping an entire parallel state somewhere. If you want to just change the cell's appearance based on select state, do it in the cell.
In your UITableViewCell subclass, override setSelected like so:
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
self.accessoryType = selected ? .checkmark : .none
}
No need to use any table view delegate methods.
Note: You have to call super.setSelected otherwise the cell doesn't keep the selected state correctly.
Swift 3.0
Using just one function to keep it simple
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
if let cell = tableView.cellForRow(at: indexPath as IndexPath) {
if cell.accessoryType == .checkmark {
cell.accessoryType = .none
} else {
cell.accessoryType = .checkmark
}
}
}
Swift 3.0
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let cell = tableView.cellForRow(at: indexPath) {
cell.accessoryType = .checkmark
}
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
if let cell = tableView.cellForRow(at: indexPath) {
cell.accessoryType = .none
}
}
Swift 4.0, all together now:
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var yourData = ["Cool","Sweet","Awesome"]
var checked = [Bool]()
override func viewDidLoad() {
super.viewDidLoad()
checked = Array(repeating: false, count: yourData.count)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return searchData.count
}
func tableView(_ tableView: UITableView, cellForRowAt IndexPath: IndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCellWithIdentifier("cell") as! UITableViewCell
//configure you cell here.
if checked[IndexPath.row] == false{
cell.accessoryType = .none
} else if checked[IndexPath.row] {
cell.accessoryType = .checkmark
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
if let cell = tableView.cellForRow(at: indexPath as IndexPath) {
if cell.accessoryType == .checkmark {
cell.accessoryType = .none
checked[indexPath.row] = false
} else {
cell.accessoryType = .checkmark
checked[indexPath.row] = true
}
}
}
}
Swift 5.0
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
if let cell = tableView.cellForRow(at: indexPath) {
resetChecks()
cell.accessoryType = .checkmark
}
}
override func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
self.tableView.cellForRow(at: indexPath)?.accessoryType = .none
}
func resetChecks() {
for i in 0..<tableView.numberOfSections {
for j in 0..<tableView.numberOfRows(inSection: i) {
if let cell = tableView.cellForRow(at: IndexPath(row: j, section: i)) {
cell.accessoryType = .none
}
}
}
}
The simple solution as others have pointed out would be to .checkmark the row in the didSelectRowAt method and set the row to .none in the didDeselectRowAtmethod as follow...
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
tableView.cellForRow(at: indexPath)?.accessoryType = .none
}
But if you have a default row selected when the table loads you first need to deselect it when other rows are selected, in that case, use the code below instead in the didSelectRowAt method.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
for row in 0..<tableView.numberOfRows(inSection: indexPath.section) {
if let cell = tableView.cellForRow(at: IndexPath(row: row, section: indexPath.section)) {
cell.accessoryType = row == indexPath.row ? .checkmark : .none
}
}
}
Updated In swift 4.2
Every New selection Remove previous Check mark
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print(self.coloursArray[indexPath.row])
self.tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
self.tableView.cellForRow(at: indexPath)?.accessoryType = .none
}
For Swift 5:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let cell = tableView.cellForRow(at: indexPath as IndexPath) {
cell.accessoryType = .checkmark
}
}
override func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
if let cell = tableView.cellForRow(at: indexPath as IndexPath) {
cell.accessoryType = .none
}
}
The simplest solution that did it for me (Swift 5.2)
override func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
// Remove checkmark from the row that is currently showing it before adding to one being selected
if let currentIndexPath = tableView.indexPathForSelectedRow {
self.tableView.cellForRow(at: currentIndexPath)?.accessoryType = .none
}
return indexPath
}
override public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark
}
For anyone using a single use of a checkmark.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
// checkmark logic
if let cell = tableView.cellForRow(at: indexPath as IndexPath) {
if cell.accessoryType != .checkmark {
resetChecks()
cell.accessoryType = .checkmark
}
}
}
func resetChecks() {
for i in 0..<tableView.numberOfSections {
for j in 0..<tableView.numberOfRows(inSection: i) {
if let cell = tableView.cellForRow(at: NSIndexPath(row: j, section: i) as IndexPath) {
cell.accessoryType = .none
}
}
}
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if self.checkedIndex == indexPath.row{
}else{
let cell = tableView.cellForRow(at: indexPath)
cell?.accessoryType = .checkmark
let indexPathh = IndexPath(row: checkedIndex, section: 0)
let UnCheckCell = tableView.cellForRow(at: indexPathh)
UnCheckCell?.accessoryType = .none
checkedIndex = indexPath.row
}
}
Since I didn't see anyone list this, you can create a custom UITableViewCell that will toggle the checkmark with selection by overriding it's setSelected() method and defaulting .selectionStyle to .gray:
class CheckableTableViewCell: UITableViewCell {
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
selectionStyle = .gray
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
accessoryType = selected ? .checkmark : .none
}
}
I have used tableView(_:didSelectRowAt:), delegate method to accomplish this feature of putting check mark on the cell and removing it when the cell is tapped again.
Here is the code:
//MARK:-create delegate methode that is fired when a cell is clicked
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath , animated: true)
if let cell = tableView.cellForRow(at: indexPath){
if cell.accessoryType == .checkmark {
cell.accessoryType = .none
}
else {
cell.accessoryType = .checkmark
}
}
}
Related
As I tried in some scenarios but not perfectly working if I select the second cell the check mark from first cell is unchecking and sometimes the functionality is not working at all until I click 10 to 20 times .here is my code.
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if tableView == switchTableView{
return self.arrdata20.count
} else
{
return self.arrdata.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if (tableView == self.switchTableView)
{
let cell:switchTableViewCell = tableView.dequeueReusableCell(withIdentifier: "cell1") as! switchTableViewCell
cell.nameLbl.text = (arrdata20[indexPath.row].name)
print(cell.nameLbl.text)
if (arrdata20[indexPath.row].emp_id == "001")
{
cell.isHidden=true
}
else{
cell.isHidden=false
}
return cell
}
else {
let cell:PartyTableViewCell = tableView.dequeueReusableCell(withIdentifier: "cell") as! PartyTableViewCell
cell.venuLbl.text = "Venu: \(arrdata[indexPath.row].place)"
cell.dateTimeLbl.text = "Date & Time: \(arrdata[indexPath.row].date)"
cell.reasonLbl.text = "Reason: \(arrdata[indexPath.row].reason)"
// cell.timeLbl.text = ""
return cell
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
var rowHeight:CGFloat = 0.0
if tableView == self.switchTableView{
if(arrdata20[indexPath.row].emp_id == "001")
{
rowHeight = 0.0
}
else
{
rowHeight = UITableViewAutomaticDimension
}
return rowHeight
}else{
return UITableViewAutomaticDimension
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
id1 = "\(arrdata[indexPath.row].id)"
print(id1)
if self.switchTableView.cellForRow(at: indexPath)?.accessoryType == UITableViewCellAccessoryType.checkmark
{
self.switchTableView.cellForRow(at: indexPath)?.accessoryType = UITableViewCellAccessoryType.none
}
else{
self.switchTableView.cellForRow(at: indexPath)?.accessoryType = UITableViewCellAccessoryType.checkmark
}
}
After selecting the tableView cells I need to get the checkmark cells details like names in the cell as shown in image below
You have to declare an array as:
var checked = [Bool]()
Then add this line of code in API call where you receive data in arraydata
self.checked = Array(repeating: false, count: self.arraydata.count)
In Table view delegate method:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell:switchTableViewCell = tableView.dequeueReusableCell(withIdentifier: "cell1") as! switchTableViewCell
//configure you cell here.
if checked[indexPath.row] == false{
cell.accessoryType = .none
} else if checked[indexPath.row] {
cell.accessoryType = .checkmark
}
cell.title.text = self. arraydata[indexPath.row]["amp_id"].string
return cell
}
add another delegate method:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
if let cell = tableView.cellForRow(at: indexPath as IndexPath) {
if cell.accessoryType == .checkmark {
cell.accessoryType = .none
checked[indexPath.row] = false
} else {
cell.accessoryType = .checkmark
checked[indexPath.row] = true
}
}
on OKClickedButtonAction:
serviceString = ""
for i in 0..<checked.count{
if checked[i] == true{
serviceString = serviceString + self.arraydata[i]["emp_id"].string! + ", "
print(serviceString)
}
}
if serviceString == ""{
self.servicesBtnLbl.text = "Tap to select"
}else{
self.servicesBtnLbl.text = serviceString
}
It's working Solution, hope it will be helpful to you.
You should update your
tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) method
like
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath) as! switchTableViewCell
if cell.accessoryType == .checkmark {
cell.accessoryType = .none
} else {
cell.accessoryType = .checkmark
}
}
But if you want the cell to keep its accessoryType even after reloading then you have to create an array to keep track of your accessoryType for each cell and update its value in the array when you update the accessoryType in UI in didSelectRowAt() and then in cellForRowAt() you have to use this array to set the accessoryType for each cell.
TableView CheckMark Cell Value Removed After Scrolling Up It will Fix
TableView in You have face a problem many times to Checkmark after scroll Up then Scroll Down To show a Your Checkmark cell is will Removed Because cell is dequeueReusableCell So This Problem Fix , you Have just put Your code and Solved Your Problem.
Any More Help So Send Massage.
Thank you So much. :)
class ViewController: UIViewController , UITableViewDataSource , UITableViewDelegate{
var temp = [Int]()
var numarr = [Int]()
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return numarr.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "id")
cell = UITableViewCell.init(style: .default, reuseIdentifier: "id")
cell?.textLabel?.text = String(numarr[indexPath.row])
if temp.contains(numarr[indexPath.row] as Int)
{
cell?.accessoryType = .checkmark
}
else
{
cell?.accessoryType = .none
}
return cell!
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath)
if temp.contains(numarr[indexPath.row] as Int)
{
cell?.accessoryType = .none
temp.remove(at: temp.index(of: numarr[indexPath.row])!)
}
else
{
cell?.accessoryType = .checkmark
temp.append(self.numarr[indexPath.row] as Int)
}
}
override func viewDidLoad() {
super.viewDidLoad()
for i in 1...100
{
numarr.append(i)
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
I think if someone were to run your code it would not show any error. But with real data it probably will. The reason is the way you store your checkmarks. You store the data of a row into the temp array when you should be storing the actualy indexPath of the array so that only that row gets the checkmark. In your case, if a row has 1 inside it's label and you click on it, that cell will be highlighted. Now if you start scrolling and another cell contains 1 then that row will also be highlighted.
I have modified your example for the case of a single section. If there is more than one section, you need to store the indexPath instead of indexPath.row.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "id")
cell = UITableViewCell.init(style: .default, reuseIdentifier: "id")
cell?.textLabel?.text = String(numarr[indexPath.row])
if temp.contains(indexPath.row) {
cell?.accessoryType = .checkmark
} else {
cell?.accessoryType = .none
}
return cell!
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath)
if temp.contains(indexPath.row) {
cell?.accessoryType = .none
temp.remove(at: indexPath.row)
} else {
cell?.accessoryType = .checkmark
temp.append(indexPath.row)
}
}
You are strongly discouraged from using a second array to keep the selected state.
This is Swift, an object oriented language. Use a custom struct for both num and the selected state.
In didSelectRowAt and didDeselectRowAt change the value of isSelected and reload the row.
And use always the dequeueReusableCell API which returns a non-optional cell.
struct Item {
let num : Int
var isSelected : Bool
}
var numarr = [Item]()
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return numarr.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "id", for: indexPath)
let item = numarr[indexPath.row]
cell.textLabel?.text = String(item)
cell.accessoryType = item.isSelected ? .checkmark : .none
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
updateSelection(at: indexPath, value : true)
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
updateSelection(at: indexPath, value : false)
}
func updateSelection(at indexPath: IndexPath, value : Bool) {
let item = numarr[indexPath.row]
item.isSelected = value
tableView.reloadRows(at: [indexPath], with: .none)
}
override func viewDidLoad() {
super.viewDidLoad()
(0...100).map{Item(num: $0, isSelected: false)}
}
I'm having an issue where when I'm selecting the cell for e.g at index 3 , it selecting cells below also at random indexes. Check and Uncheck cell is working but for some reasons when selecting a cell it is selecting other cells as well. My array is returning 120 rows in total. I have selected multiple touch. Thank you for the help.
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return arrayVerbCount.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell = self.tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! MesTalentsChoixCell
cell.verb!.text = arrayVerbCount[indexPath.row].verb
if cell.isSelected
{
cell.isSelected = false
if cell.accessoryType == UITableViewCellAccessoryType.none
{
cell.accessoryType = UITableViewCellAccessoryType.checkmark
}
else
{
cell.accessoryType = UITableViewCellAccessoryType.none
}
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){
let cell = tableView.cellForRow(at: indexPath)
if cell!.isSelected
{
cell!.isSelected = false
if cell!.accessoryType == UITableViewCellAccessoryType.none
{
cell!.accessoryType = UITableViewCellAccessoryType.checkmark
}
else
{
cell!.accessoryType = UITableViewCellAccessoryType.none
}
}
}
My custom cell class:
class MesTalentsChoixCell: UITableViewCell {
#IBOutlet weak var verb: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
You should do like this way, this is very much easy solution if there is only one section.
Initialize selectedItems array like this,
var selectedItems: [Int] = []
Find UITableViewDataSource method below
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell") as! CustomCell
cell.tmpValue.text = data[indexPath.row]
if selectedItems.contains(indexPath.row) {
cell.accessoryType = .checkmark
} else {
cell.accessoryType = .none
}
return cell
}
Find UITableViewDelegate Method below.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
if selectedItems.contains(indexPath.row) {
let index = selectedItems.index(of: indexPath.row)
selectedItems.remove(at: index!)
} else {
selectedItems.append(indexPath.row)
}
tableView.reloadRows(at: [indexPath], with: .none)
}
Code will be changed depending on your requirement and custom cell. Hope you can do it your way. Thank you.
UPDATE
You can even use Set also like this way,
var setSelectedItems: Set<Int> = []
UITableViewDataSource method,
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell") as! CustomCell
cell.tmpValue.text = data[indexPath.row]
if setSelectedItems.contains(indexPath.row) {
cell.accessoryType = .checkmark
} else {
cell.accessoryType = .none
}
return cell
}
UITableViewDelegate method,
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
if setSelectedItems.contains(indexPath.row) {
setSelectedItems.remove(indexPath.row)
} else {
setSelectedItems.insert(indexPath.row)
}
tableView.reloadRows(at: [indexPath], with: .none)
}
Make bool array for stability while scrolling i.e.
var arrStatusBool = [Bool]()
Now set value at indexPath.row in didSelectRowAt
public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
if self.arrStatusBool[indexPath.row]
{
self.arrStatusBool[indexPath.row] = false
}
else
{
self.arrStatusBool[indexPath.row] = true
}
}
And also put this in cellForRowAt to avoid scrolling issue.
if self.arrStatusBool[indexPath.row]
{
tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark
}
else
{
tableView.cellForRow(at: indexPath)?.accessoryType = .none
}
hope this help!
For multiple selection you should track selected cells in a Dictionary for convenience faster access to selected and unselected indexPaths allowing you use multiple sections because the key value of our Dictionary is a string formed by (IndexPath.section)+(IndexPath.row) which is always unique combination
var selectedIndexPaths : [String:Bool] = [:]
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let currentIndexPathStr = "\(indexPath.section)\(indexPath.row)"
if(self.selectedIndexPaths[currentIndexPathStr] == nil || !self.selectedIndexPaths[currentIndexPathStr]!) {
self.selectedIndexPaths[currentIndexPathStr] = true
}else{
self.selectedIndexPaths[currentIndexPathStr] = false
}
self.tableView.reloadRows(at: [indexPath], with: .automatic)
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "npCell", for: indexPath) as! NewPlaylistTableViewCell
cell.mTitle.text = musics[indexPath.row]["title"] as! String?
cell.mArtist.text = musics[indexPath.row]["artist"] as! String?
cell.accessoryType = .checkmark
let currentIndexPathStr = "\(indexPath.section)\(indexPath.row)"
if(self.selectedIndexPaths[currentIndexPathStr] == nil || !self.selectedIndexPaths[currentIndexPathStr]!) {
cell.accessoryType = .none
}
return cell
}
Results
Just a minor change
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell = self.tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! MesTalentsChoixCell
cell.verb!.text = arrayVerbCount[indexPath.row].verb
if cell.isSelected
{
cell.accessoryType = UITableViewCellAccessoryType.checkmark
}
else
{
cell.accessoryType = UITableViewCellAccessoryType.none
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){
let cell = tableView.cellForRow(at: indexPath)
//toggle the state
cell!.isSelected = !cell!.isSelected
if cell!.isSelected
{
cell!.accessoryType = UITableViewCellAccessoryType.checkmark
}
else
{
cell!.accessoryType = UITableViewCellAccessoryType.none
}
}
Note: you should also create method for common code :-)
I am having a problem in uitableview whenever I select one cell 4th no cell auto get selected... I am tired of this problem someone please help here is my didselectrowfunc..
////////////////For Adding Check Box////////////////////////
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if tableView.cellForRow(at: indexPath)?.accessoryType == UITableViewCellAccessoryType.checkmark
{
if selectedDisease.count > 0
{
let no = selectedDisease.index(of: finall[indexPath.row])
selectedDisease.remove(at: no!)
tableView.cellForRow(at: indexPath)?.accessoryType = UITableViewCellAccessoryType.none
print(selectedDisease)
}
else
{
selectedDisease = [""]
}
}
else
{
if selectedDisease.contains("")
{
selectedDisease.removeAll()
var name = finall[indexPath.row]
selectedDisease.append(name)
tableView.cellForRow(at: indexPath)?.accessoryType = UITableViewCellAccessoryType.checkmark
print(selectedDisease)
}
else
{
tableView.cellForRow(at: indexPath)?.accessoryType = UITableViewCellAccessoryType.checkmark
selectedDisease.append(finall[indexPath.row])
//selectedDisease = [finall[indexPath.row]]
print(selectedDisease)
}
}
}
/////////CellForRowAt///////////////
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "diseasetable", for: indexPath) as! FoodTableViewCell
cell.DiseaseName.text = finall[indexPath.row]
//indexsave.append(indexPath.row)
return cell
}
Try this logic hope this will solve your problem
let dict = [NSIndexPath: String]()
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
if let _ = // dict contains value at indexpath {
cell.accessoryType = .Checkmark
} else {
cell.accessoryType = .None
}
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if ( // dict contains value == indexpath) {
// remove value from dict
} else {
//add value to dict
}
tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)
}
Just take the advantage of prepareForReuse method of UITableViewCell. In your FoodTableViewCell class implement the prepareForReuse menthod like following
class FoodTableViewCell: UITableViewCell
{
override func awakeFromNib()
{
super.awakeFromNib()
// Initialization code
}
override func setSelected(selected: Bool, animated: Bool)
{
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
override func prepareForReuse()
{
self.accessoryType = UITableViewCellAccessoryType.none
//add code to reset selection if there is any other selection mechanism
}
}
I have a tableview where not all of the cells are visible at once. I am trying to make it so that when a row is tapped it adds a checkmark accessory to the cell. My issue is that it adds it to other rows as well. In my table view there are 4 rows fully showing and a fifth one barely showing. If I check the first box it will then add a check mark to every fifth box (e.g. indexPath.row = 0,5,10,15...) despite the indexPath.row being different.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell: DropDownMenuCell = tableView.dequeueReusableCellWithIdentifier("DropDownMenuCell", forIndexPath: indexPath) as! DropDownMenuCell
cell.dropDownCellLabel?.text = DropDownItems[indexPath.row].Name
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let selectedCell: DropDownMenuCell = tableView.cellForRowAtIndexPath(indexPath) as! DropDownMenuCell
print(indexPath.row)
if selectedCell.accessoryType == .None {
selectedCell.accessoryType = .Checkmark
} else {
selectedCell.accessoryType = .None
}
}
Edit: Apologies for the duplicate, my initial search for this question didn't show the other question. I got a working answer here in swift already or I would try and go through the objective c post to solve my problem.
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)
In Swift 3, this should help:
import UIKit
class ViewController: UITableViewController {
let foods = ["apple", "orange", "banana", "spinach", "grape"]
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return foods.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) ->
UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = foods[indexPath.row]
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
if tableView.cellForRow(at: indexPath)?.accessoryType == UITableViewCellAccessoryType.checkmark
{
tableView.cellForRow(at: indexPath)?.accessoryType = UITableViewCellAccessoryType.none
}
else
{
tableView.cellForRow(at: indexPath)?.accessoryType = UITableViewCellAccessoryType.checkmark
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}