How to select and deselect a row by tapping on it - ios

I have a UITableView with an UITableViewCell, and I want to select them by clicking on it and deselect them by another clicking on them.
First, I have tried it with
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
// code
}
But I have noticed that this function don't get performed when you click a second time on a cell; it gets performed when you click on another cell.
But I want that you can click on several cells which are checked when you click on them.
So I have made this code (simplified):
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("Selected")
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! LektionTableViewCell
if cell.accessoryType == .none {
print("Type = none")
cell.accessoryType = .checkmark
Lektion.insert(Dateien[indexPath.row], at: Lektion.count)
} else if cell.accessoryType == .checkmark {
print("Type = check")
cell.accessoryType = .none
Lektion.remove(at: indexPath.row)
}
}
But it doesn't work correctly:
When I click on a cell, the text automatically turn to "Label" (The text it has in the view builder)
When I click on a cell with a check, the check doesn't vanish and Xcode says "Type = none"; that is wrong.
Can anybody help me?

I can't comment so I add it here.
From your code we don't see where you store the data for populating your cells. So I don't know if this can help you but suppose you have an array with your objects, one approach would be to set a "isSelected" variable on your object on the didSelectRowAt indexPath method and then call tableview.reloadData(). Something like this:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
myObjects[indexPath.row].isSelected = !myObjects[indexPath.row].isSelected
tableView.reloadData()
}
Then on the cellForRowAtIndexPath method, when you create your cells you could easily set the accessoryType to either .checkmark or .none depending on the flag of your object.
Like this:
cell.accessoryType = myObjects[indexPath.row].isSelected ? .checkMark : .none
Hope that helps.

Remove following code from your didSelect method, as it dequeReusableCell should not be used outside cellForRowAtIndexPath.
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! LektionTableViewCell
if cell.accessoryType == .none {
print("Type = none")
cell.accessoryType = .checkmark
Lektion.insert(Dateien[indexPath.row], at: Lektion.count)
} else if cell.accessoryType == .checkmark {
print("Type = check")
cell.accessoryType = .none
Lektion.remove(at: indexPath.row)
}
You can get cell instance using cellForRowAtIndexPath inside idSelectRow
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let cell = tableView.cellForRow(at: IndexPath) as? LektionTableViewCell {
// Perform your operations here.....
}
}
Now, solution to your query, that for didSelect is not called upon click (unless you select another row). Allow multiple selection to your table view.
Note: Use a flag (boolean) variable in your table array to set selection status while your table is loading data.

Related

How to save and persist selected cell check mark in UITableView using Swift?

In myscenario, I am trying to load JSON data into my tableview. Here, I am using multiple cell selection in a tableview. I need to persist selected cell checkmark. if I go another view controller and comeback to see tableview selected check mark need to show.
My Code
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.tableView.deselectRow(at: indexPath, animated: true)
let item = searching ? filteredData[indexPath.row] : membersData[indexPath.row]
if selectedRows.contains(indexPath.row) {
tableView.cellForRow(at: indexPath)?.accessoryType = .none
} else {
tableView.cellForRow(at: indexPath)?.accessoryType =
}
}

How to access specific row by index

I've a table view controller in which I want to dynamically create a row (cell). How can I access row by index number in Swift? The following is what I did and now I'm stuck here.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "teamStats", for: indexPath) as! TeamStatsTableViewCell
return cell
}
This is my TableViewController code in which I want to check if the row is at a specific index number.
This method is a delegate method which will be called every time a cell is displayed on your UITableView. So if you want to do something with a cell in a particular index, you do the following. Please go through Apple docs and get a better understanding of what delegate methods are.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "teamStats", for: indexPath) as! TeamStatsTableViewCell
if indexPath.row == requiredIndex {
//Do something.
}
if indexPath.row == lastIndex { // you have the last index with you. replace this variable with that.
cell.firstlabel.text = ""
}
return cell
}
Please try this code:
if indexPath.row == 1{
//Your code
}
You can check the section :
if indexPath.section == 1{
}
It may helps to you.Thank you

How to save an indexPath in a user default and how to have a cell in a tableview pre-selected as it is loaded? (xcode 8, swift 3.0)

So I have been looking all over the internet for an answer to this but to no avail. Basically, I have code to have cells in a tableview have a check mark when selected, which works fine. However, when selected, I want the indexPath to be saved in a user default so that the next time the user views it, that particular cell that she had selected before can be pre-selected:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let cell = tableView.cellForRow(at: indexPath) {
cell.accessoryType = .checkmark
UserDefaults.standard.set(indexPath as IndexPath, forKey: "OnHomeShow")
}
}
override func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
if let cell = tableView.cellForRow(at: indexPath) {
cell.accessoryType = .none
}
}
The saving in the user default didn't work! Anyone able to help? Furthermore, how do I get it so that I can have a pre-selected cell? I used this code here:
override func viewDidAppear(_ animated: Bool) {
if let x = UserDefaults.standard.object(forKey: "OnHomeShow") as? IndexPath
{
//I want to pre-select the cell set by the user-default
}
else
{
//I want to pre-select the first cell
}
}
But I have no idea what code to put to select a cell programmatically! Anyone know how to help? Thanks!

swift 3 - ViewController not deselecting selected rows in a UITableView

I have a tableview where the user is able to select multiple rows (these rows are distinguished by a checkbox in the row). For some reason, however, I can't implement the functionality to deselect any selected row. Can somebody tell me what I'm missing?
SomeViewController.m
#objc class SomeViewController: UIViewController, NSFetchedResultsControllerDelegate, UITableViewDataSource, UITableViewDelegate {
var deviceArray:[Device] = []
// [perform a fetch]
// [insert fetch results into deviceArray to be displayed in the tableview]
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "customcell", for:
indexPath)
// Set up the cell
let device = self.deviceArray[indexPath.row]
cell.textLabel?.text = device.name
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.tableView(tableView, cellForRowAt: indexPath).accessoryType = UITableViewCellAccessoryType.checkmark
NSLog("Selected Row")
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
self.tableView(tableView, cellForRowAt: indexPath).accessoryType = UITableViewCellAccessoryType.none
NSLog("Deselected Row")
}
}
More info:
Looking at the debug logs inserted, I can share the following observations:
When selecting an unselected row, the console prints "Selected Row"
If I click the same row from observation #1, the console prints "Selected Row" only
If I click on any other row, the console prints "Deselected Row" and then "Selected Row"
If I click on the same row as observation #3, the console prints "Selected Row" only.
So, it looks like everytime I click on a different row, tableView: didDeselectRowAt: gets called; however, checkmarks in the clicked row do not go away.
More Info 2:
So I'm new to storyboards and didn't set the "allowsMultipleSelection" property. Going into the Attributes Inspector, this is what my settings look like:
Now, when pressing the same row in the tableView, my console confirms that the app is alternating between tableView:didSelectRowAt: and tableView:didDeselectRowAt:, however, the checkmark doesn't disappear; once the user selects a row, the checkmark remains selected even when tableView:didDeselectRowAt: is called. What else am I missing?
First off make sure your datasource AND delegate outlets are set if you are setting them from storyboard.
Another thing is you need to set allowsMultipleSelection property to true to get the didSelect, didDeselect methods to get called in the behavior you want. Otherwise it will always call didSelect for the cell you tapped on and didDeselect for the most previously selected cell.
The other thing to note is that you are referencing self.tableView when setting your cell.accessoryType property. This may be different instance of the tableView being passed into the delegate method. I recommend a guard let statment to ensure the code setting the accessory type only applies if the tableView being passed into the function. Here is code I used to get it to work.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
//Notice I use tableView being passed into func instead of self.tableView
guard let cell = tableView.cellForRow(at: indexPath) else {
return
}
cell.accessoryType = .checkmark
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
guard let cell = tableView.cellForRow(at: indexPath) else {
return
}
cell.accessoryType = .none
}
If you want user to be able to select multiple cells, you need to set tableView.allowsMultipleSelection = true in the viewDidLoad method or set multiple selection in the attributes inspector.

Table view marking more than one cell Swift 3

I have a VERY annoying problem.
I have a tableView with more or less 50 cells, displaying some options to which I can select the ones I want. I read in Apple's documentation that by default the cells are reused when they are not displayed. With this, if I select the first cell, every 6 cells 1 is marked, that is, if I select the first 6 cells, ALL cells in the table are marked!
My table view allows multiple selections. The selection is being made like this:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.cellForRow(at: indexPath)?.accessoryType = UITableViewCellAccessoryType.checkmark
}
How do I solve this? I know you have such a "prepareForReuse ()" for the subclass, would that be the solution? If so, can you give me an example of how you would do it?
here is code it may help you
var arr_selectedindePath = NSMutableArray()
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
if arr_selectedindePath .contains(indexPath) {
arr_selectedindePath .remove(indexPath)
tableView.cellForRow(at: indexPath)?.accessoryType = UITableViewCellAccessoryType.none
}
else
{
arr_selectedindePath .add(indexPath)
tableView.cellForRow(at: indexPath)?.accessoryType = UITableViewCellAccessoryType.checkmark
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: "cell")!
if arr_selectedindePath .contains(indexPath) {
cell.accessoryType = .checkmark
}
else
{
cell.accessoryType = .none
}
}
You will need to update your data model accordingly so that when cellForRowAtIndexPath is called it displays cells with updated content.
If you don't use a datamodel you will need to store the indexPath's in a mutable array and make a check whether the current indexPath is marked or not.
Hope this helps.
In your custom cell
1.Create a delegate
protocol CellDelegate {
func didTapOnButton(_ cell:Cell)
}
2. Declare delegate
var delegate:CellDelegate?
3.Override this method
override func prepareForReuse() {
super.prepareForReuse()
self.delegate = nil
}
#IBAction func buttonTapped()
{
self.delegate!.didTapOnButton(self)
}
In your tableview controller
1.Implement delegate method
2.Inside cellForRowAtIndexPath assign tag value to cell.button
3.implement this method
func didTapOnButton(_ cell: Cell) {
print("off button clicked at index \(cell.button.tag)")
}

Resources