UITableViewCell checkmark to be toggled on and off when tapped
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
}
Swift: Toggling checkmark to ON for last selected cell only - not working
First tell your tableview it can only select one cell at a time:
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.allowsMultipleSelection = false
}
Then, let's analyse your code, you're getting the section at which the present cell is being selected and calculating the number of rows in that specific section. You iterate on the rows of that section and checking if you have a cell at the given indexPath (I guess it always evaluates to true because you always have a cell at that indexPath, you didn't put a condition depending on the value of your for-loop). Then you tell the cell to have a checkmark if the row in the for-loop equals the row of the cell being currently selected by the user.
As your function is written, there is no reason why only the last in the section would get the checkmark, but you overcomplicated the matter.
Your cell is drawn in the following method and so should the accessory initially.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "YourCell", for: indexPath)
cell.textLabel?.text = "your text"
cell.accessoryType = cell.isSelected ? .checkmark : .none
// cell.selectionStyle = .none if you want to avoid the cell being highlighted on selection then uncomment
return cell
}
Then you can just say that the accessory type should be .checkmark in tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
and .none in tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath)
.Here is how to do it and you should be good, if not let me know and I can edit again.
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.cellForRowAtIndexPath(indexPath)?.accessoryType = .checkmark
}
override func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
tableView.cellForRowAtIndexPath(indexPath)?.accessoryType = .none
}
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
}
}
UITableViewCell checkmark change on select
Keep a property in your view controller called
selectedRow
, which represents the index of a row that represents the checked item in a table section.In your view controller's
-tableView:cellForRowAtIndexPath:
delegate method, set theaccessoryType
of thecell
toUITableViewCellAccessoryCheckmark
if the cell'sindexPath.row
equals theselectedRow
value. Otherwise, set it toUITableViewCellAccessoryNone
.In your view controller's
-tableView:didSelectRowAtIndexPath:
delegate method, set theselectedRow
value to theindexPath.row
that is selected, e.g.:self.selectedRow = indexPath.row
Want accessory checkmark to show only when tapped on the right
Instead of the built-in checkmark accessory type, why not provide, as accessory view, an actual button that the user can tap and that can display the checkmark? The button might, for example, display as an empty circle normally and as a circle with a checkmark in it when the user taps it.
Otherwise, you're expecting the user to guess at an obscure interface, whereas, this way, it's perfectly obvious that you tap here to mark the task as done.
Example:
To accomplish that, I created a button subclass and set the accessoryView
of each cell to an instance of it:
class CheckButton : UIButton {
convenience init() {
self.init(frame:CGRect.init(x: 0, y: 0, width: 20, height: 20))
self.layer.borderWidth = 2
self.layer.cornerRadius = 10
self.titleLabel?.font = UIFont(name:"Georgia", size:10)
self.setTitleColor(.black, for: .normal)
self.check(false)
}
func check(_ yn:Bool) {
self.setTitle(yn ? "✔" : "", for: .normal)
}
override init(frame:CGRect) {
super.init(frame:frame)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
The title of the button can be the empty string or a checkmark character, thus giving the effect you see when the button is tapped. This code comes from cellForRowAt:
:
if cell.accessoryView == nil {
let cb = CheckButton()
cb.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
cell.accessoryView = cb
}
let cb = cell.accessoryView as! CheckButton
cb.check(self.rowChecked[indexPath.row])
(where rowChecked
is an array of Bool).
Swift | UIViewTable changes checkmark when scrolled off screen
The error occurs because you toggle the checked
state always in configureCheckmark
. So whenever cellForRow
is called for this row the state is toggled.
Actually an extra method configureCheckmark
is not needed. Put the line to set the checkmark in cellForRow
but don't change the state.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ChecklistItem", for: indexPath)
let item = todoList.items[indexPath.row]
configureText(for: cell, with: item)
cell.accessoryType = item.checked ? .checkmark : .none
return cell
}
In didSelectRowAt
toggle checked
in the model and reload the row
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
todoList.items[indexPath.row].checked.toggle()
tableView.reloadRows(at: [indexPath], with: .none)
}
The method toggleChecked()
in ChecklistItem
is redundant, too. There is a toggle()
method in Bool
.
And consider to use structs rather than classes.
UITableviewCell - Clicking on empty checkmark circle in edit mode does not select cell
The problem ended up being that I was setting a backgroundView
on my custom table cell and that was preventing the touches from getting to the right target.
Related Topics
Change Color of Back Button in Navigation Bar
Creating a Navigationcontroller Programmatically (Swift)
How to Change the Tint Color of the Clear Button on a Uitextfield
Minimum and Maximum Date in Uidatepicker
How to Change the Uinavigationcontroller Back Button Name
The Supportedinterfaceorientations Method Doesn't Override Any Method from Its Superclass
Offscreen Uitableviewcells (For Size Calculations) Not Respecting Size Class
Swift 2.0 Sorting Array of Objects by Property
How to Convert Nsdate into Unix Timestamp iPhone Sdk
How to Switch to Different Storyboard for iPhone 5
iOS - Parse Issues in Nsobjcruntime, Nszone, and Nsobject
How to Restrict Special Characters in Uitextfield Except Dot and Underscores
Button in Uitableviewcell Not Responding Under iOS 7
Implement Dark Mode Switch in Swiftui App