UITableView checkmark hide when scrolling - swift

When I scroll the screen, the upper markings disappear. I've tried some solutions found here, but none worked ...
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: .default, reuseIdentifier: "cell")
cell.textLabel?.text = players[indexPath.row]
cell.textLabel?.textColor = UIColor.white
cell.backgroundColor = colorForIndex(index: indexPath.row)
cell.textLabel?.font = UIFont(name: "Chalkboard SE", size: 20)
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.tableView.deselectRow(at: indexPath, animated: true)
if let cell = tableView.cellForRow(at: indexPath){
if (cell.accessoryType == .none) {
cell.accessoryType = .checkmark
let player = players[indexPath.row]
playersSelecteds.append(player)
} else {
cell.accessoryType = .none
let player = players[indexPath.row]
if let position = playersSelecteds.index(of: player) {
playersSelecteds.remove(at: position)
}
}
}
}

You should have a model for check-marked cells. because every time you scroll, the cells being reload based on your tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell method.
So, for example add a model like this:
var playersCheckmarked: [Bool] = []
Then add in viewDidLoad some boolean to this array as many as players array have objects. Next in override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) method set playersCheckmarked[indexPath.row] = true or playersCheckmarked[indexPath.row] = false based on user selection.
And of course in override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell method add this line:
cell.accessoryType = playersCheckmarked[indexPath.row] == true .checkmark : .none

Related

How can I stop my UITableView from reusing cells?

I have a UITableView containing about 30 cells. The user is only able to select one. Once a cell is selected it shows a checkmark. But the problem is whenever I scroll down the UITableView it shows cells i never clicked with a checkmark beside them. What is the proper way to fix this?
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return breedNameArray.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Bcell")
let cell = tableView.dequeueReusableCell(withIdentifier: "Bcell", for: indexPath)
//cell.accessoryType = UITableViewCell.AccessoryType.checkmark
cell.textLabel?.text = breedNameArray[indexPath.item]
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath as IndexPath)
tableView.register(UINib(nibName: "BBcell", bundle: nil), forCellReuseIdentifier: "Cell")
//let cell = tableView.dequeueReusableCell(withIdentifier: "Breeds", for: indexPath)
//tableView.deselectRow(at: tableView.indexPathForSelectedRow!, animated: true)
tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark
}
override func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Bcell")
//let cell = tableView.dequeueReusableCell(withIdentifier: "Breeds", for: indexPath)
tableView.cellForRow(at: indexPath)?.accessoryType = .none
}
The reason you are seeing cells getting checkmarks when scrolling is because the call to tableView.dequeueReusableCell(withIdentifier:"Bcell", for: indexPath) in cellForRowAt reuses already allocated UITableViewCell objects that have the identifier "Bcell". The UITableView does not automatically reset the properties of the reused UITableViewCell objects when reused in this way.
Since you are only allowing one UITableViewCell to be selected at a time, a simple solution would be to add a local variable to keep track of the selected IndexPath, and then use the local variable to set the accessoryType accordingly in cellForRowAt. Here is the code to illustrate what I mean:
// The local variable to keep track of the selected IndexPath
var selectedIndexPath = IndexPath()
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return breedNameArray.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Bcell")
let cell = tableView.dequeueReusableCell(withIdentifier: "Bcell", for: indexPath)
// Use selectedIndexPath to set the accessoryType as .checkmark or .none
if indexPath == selectedIndexPath {
cell.accessoryType = UITableViewCell.AccessoryType.checkmark
} else {
cell.accessoryType = UITableViewCell.AccessoryType.none
}
cell.textLabel?.text = breedNameArray[indexPath.item]
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// Set the selectedIndexPath
selectedIndexPath = indexPath
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath as IndexPath)
tableView.register(UINib(nibName: "BBcell", bundle: nil), forCellReuseIdentifier: "Cell")
//let cell = tableView.dequeueReusableCell(withIdentifier: "Breeds", for: indexPath)
//tableView.deselectRow(at: tableView.indexPathForSelectedRow!, animated: true)
tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark
}
override func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
// Un-Set the selectedIndexPath
selectedIndexPath = IndexPath()
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Bcell")
//let cell = tableView.dequeueReusableCell(withIdentifier: "Breeds", for: indexPath)
tableView.cellForRow(at: indexPath)?.accessoryType = .none
}

Weird display behaviour when selecting tableview row

I have this table view, that populates through Core Data. Everything looks fine, even when scrolling, until I press and hold any row - then that row distorts like in the second image below.
(source: staticflickr.com)
(source: staticflickr.com)
Here's the code to display the tableview
override func viewDidLoad() {
super.viewDidLoad()
animateBackground(colors)
tableView.delegate = self
tableView.dataSource = self
tableView.fetchData(fetchedResultsController as! NSFetchedResultsController<NSFetchRequestResult>)
self.tableView.tableFooterView = UIView(frame: .zero)
}
func numberOfSections(in tableView: UITableView) -> Int {
guard fetchedResultsController.sections?.count != nil else { return 0 }
return fetchedResultsController.sections!.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
guard fetchedResultsController.sections != nil else { return 0 }
let data = fetchedResultsController.sections![section]
return data.numberOfObjects
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "SkillCell", for: indexPath) as! SkillCell
configureCell(cell: cell, indexPath: indexPath as NSIndexPath)
return cell
}
func configureCell(cell: SkillCell, indexPath: NSIndexPath) {
let skill = fetchedResultsController.object(at: indexPath as IndexPath)
cell.skill = skill
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { }
}
From the code above, everything looks normal, yet this distortion occurs. Please help me to see why and how to stop it happening.
As the comment suggests, it's just a visual effect called selectionStyle of your UITableViewCell. Inside your cellForRowAt indexPath method, you can disable it like:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "myCell") as! MyCell
cell.selectionStyle = .none // this removes the effect.
return cell
}
yes you should set tableView selection style to none.
1.Select the tableview in storyboard in the right panel set selection style to none.
or
2.in your tableview cellforrow method set
tableView.selectionstyle = none

How to keep checkmarks from disappearing from TableView when scrolling

I currently have a tableView that gets it data from a API that outputs JSON and allows the user to tap to add a checkmark accessory to the right side. The issue I am having is after tapping on a cell in a long list of records and scrolling that row out of view, the checkmark disappears.
This is what I am doing, but when scrolling the checkmarks still disappear when off screen:
var selectedIndexPaths: Set<String> = []
override func tableView(_ tableView: UITableView, cellForRowAt
indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "testcell",
for: indexPath)
if selectedIndexPaths.contains(indexPath.description) {
cell.accessoryType = .checkmark
} else {
cell.accessoryType = .none
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath:
IndexPath) {
selectedIndexPaths.insert(indexPath.description)
tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark
}
override func tableView(_ tableView: UITableView, didDeselectRowAt
indexPath: IndexPath) {
selectedIndexPaths.remove(indexPath.description)
tableView.cellForRow(at: indexPath)?.accessoryType = .none
}
Why is the issue still persisting?

Hide button in another cell when cell is tapped

I have a `tableView with three cells. In two of them I have a button. I would like to hide the button in the other cell, when one of the cells is tapped.
I have tried some solutions in didSelectRowAt but have not been able to hide the buttons:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.row == 1 {
if let cell = tableView.cellForRow(at: indexPath) as? ComposeCell1 {
cell.compose.isHidden = true
if let cell2 = tableView.cellForRow(at: indexPath) as? ComposeCell2 {
cell2.compose.isHidden = true //I can reach the cell from here, but its not hiding the button
}
}
} else if indexPath.row == 2 {
if let cell = tableView.cellForRow(at: indexPath) as? ComposeCell2 {
cell.compose.isHidden = true
}
}
}
Try to track the index for the pressed button with a variable. And use the variable in tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell to update the button's visibility. Only thing you need to do in didSelectRowAt is assign the index value the variable and reload the table view
var selectedIndex: Int?
....
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
selectedIndex = indexPath.row
tableView.reloadData()
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
.....
cell.compose.isHidden = indexPath.row != selectedIndex
.....
return cell
}

Cell does not get deselected while scrolled back

I have a weird problem. While I select a cell with changing the background color of one UIView component, then I scroll down and selected cell going to be out of bounds of the view. I do select new cell -> previous one should get unselected, but it does not. Because when I back I do have 2 selected cells.
var lastSelectedAtIndexPath: IndexPath?
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
switch tableView {
case myTableView:
if let cell = myTableView.cellForRow(at: indexPath) as? MyTableViewCell {
cell.checkMarkBorder.backgroundColor = UIColor.darkGreyFts
lastSelectedFuelAtIndexPath = indexPath
}
default:
break
}
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
switch tableView {
case myTableView:
if let cell = fuelTableView.cellForRow(at: indexPath) as? MyTableViewCell {
cell.checkMarkBorder.backgroundColor = UIColor.white
}
default:
break
}
}
And iside cellForRowAt I have :
let cell = myTableView.dequeueReusableCell(withIdentifier: "myCell") as! MyTableViewCell
if let lastIndexPath = lastSelectedFuelAtIndexPath {
myTableView.deselectRow(at: lastIndexPath, animated: true)
}
cell.myImage.image = UIImage(named: fuelType)?.withRenderingMode(.alwaysTemplate)
cell.myNameLabel.text = "Test"
Any ideas what is going on?
Thanks in advance!
Don't make changes on cell outside cellForRowAt always change your dataSource and use dataSource in cellForRowAt then in didSelectRowAt and didDeSelectRowAt reload the row.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = myTableView.dequeueReusableCell(withIdentifier: "myCell") as! MyTableViewCell
cell.myImage.image = UIImage(named: fuelType)?.withRenderingMode(.alwaysTemplate)
cell.myNameLabel.text = "Test"
cell.checkMarkBorder.backgroundColor = lastSelectedFuelAtIndexPath == indexPath ? UIColor.darkGreyFts : UIColor.white
return cell
}
Now in didSelectRowAt and didDeSelectRowAt update the lastSelectedFuelAtIndexPath reload the row.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if tableView == myTableView {
lastSelectedFuelAtIndexPath = indexPath
myTableView.reloadRows(at: [indexPath], with: .automatic)
}
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
if tableView == myTableView {
lastSelectedFuelAtIndexPath = nil
myTableView.reloadRows(at: [indexPath], with: .automatic)
}
}