How to maintain highlighted multiple UITableView rows after reloading UITableView? - swift

I have a UITableView.
I can select multiple cells make them highlighted.
But, whenever I reload App, the selected and highlighted state disappears.
I think I need to put some codes in 'viewDidAppear' and 'didSelectRowAt'. But I don't have any idea of specific codes.
What do I have to put in this syntax?
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
tableView.reloadData()
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
}
}

I recommend u add to dataSource item field selected, and in method cellForRowAtindexPath configure by your dataSource items.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cellClass = (self.cellClass(for: indexPath) ?? self.cellClasses.first) else { return UITableViewCell() }
let cell = tableView.dequeueReusableCell(withIdentifier: cellClass.identifier, for: indexPath)
if let configurable = cell as? ConfigurableComponent, let object = self.object(at: indexPath) {
let item = self.dataSource[indexPath.row]
configurable.selected = item.selected
}
return cell
}
When call didSelectRowAt, just take item and change selected field, sample:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let item = self.dataSource[indexPath.row]
item.selected = !item.selected
tableView.reloadData()
}

Related

How to change editing style for specific cell in tableview

I have a tableview where the editingstyle is .delete for all the cells. But I want to have some specific cells that doesnt have editingstyle (so that you can't swipe them, .none). Anyone have any suggestions for how to implement this?
I tried to write something like UITableViewCell.EditingStyle.none for that specific row but that didnt work.
Thanks in advance, Pontus
Consider the following example:
class ViewController: UITableViewController {
private let arr = (1...10).map { "Item \($0)" }
override func viewDidLoad() {
super.viewDidLoad()
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arr.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell")
cell?.textLabel?.text = arr[indexPath.row]
return cell ?? UITableViewCell()
}
override func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCell.EditingStyle {
if indexPath.row == 2 {//<- Your condition
return .none
} else {
return .delete
}
}
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
}
So the key is to use editingStyleForRowAt in order to change the style for a specific cell (or even multiple cells) (see the documentation for further reference: https://developer.apple.com/documentation/uikit/uitableviewdelegate/1614869-tableview).

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

Nil is returned everytime I try to access textLabel of UITableViewCell

I am trying to get the text of the UITableViewCell in my
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let selectedCell = tableView.cellForRow(at: indexPath)
let cellLabel = selectedCell!.textLabel!.text
print(cellLabel)
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let musicCell = music[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "MusicCell") as! MusicCell
cell.setMusic(music: musicCell)
return cell
}
but its returning nill.
MusicListView is my UIViewController and I have extended it
extension MusicListView: UITableViewDataSource, UITableViewDelegate {
}
Any help will be greatly appreciated :)
So as suggested by others I accessed the required data from the data model.
I wrote a little function to access the data model
func findMusic(id : Int) -> String {
currentTitle = songList[id].title!
return currentTitle
}
and called it everytime a user tapped on a cell
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
currentTitle = findMusic(id: indexPath.row)
playSong(title: currentTitle)
}

didSelectRowAt indexPath does not when tapped (but does trigger when cell is swiped in either direction)

This is a weird (but should be simple) one. I am simply trying to tap a custom UITableViewCell and trigger a segue to go to another ViewController. didSelectRowAt indexPath does not trigger when the cell is tapped, but it oddly enough does when the cell is swiped from right to left or left to right.
My didSelectRowAt indexPath:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("You selected cell number: \(indexPath.row)!")
self.performSegue(withIdentifier: "mySegue", sender: self)
}
(as suggested here)
My ViewController:
import UIKit
class myViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UIPickerViewDelegate {
var myData = NSDictionary()
override func viewDidLoad() {
super.viewDidLoad()
fetchMyData()
self.tableView.delegate = self
self.tableView.dataSource = self
self.tableView.rowHeight = 100
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func fetchMyData() {
// ... fetches my data
}
////////////////////////////////////////////////
//Table view data source
//set number of sections in table
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
//set number of rows in table
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return myData.count
}
//delegate information to cells in table rows
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
print("running tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell...")
// Dequeue cell
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! myCustomCell
cell.cellAmount!.text = "Hello World"
cell.cellTextField2!.text = "Some info"
cell.cellTextField3!.text = "Some other info"
cell.backgroundCardView.backgroundColor = UIColor.red
cell.backgroundCardView.layer.cornerRadius = 8.0
cell.backgroundCardView.layer.masksToBounds = false
cell.backgroundCardView.layer.shadowColor = UIColor.black.withAlphaComponent(0.9).cgColor
cell.backgroundCardView.layer.shadowOffset = CGSize(width: 0, height: 0)
cell.backgroundCardView.layer.shadowOpacity = 0.9
print("finished tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell...")
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("You selected cell number: \(indexPath.row)!")
self.performSegue(withIdentifier: "mySegue", sender: self)
}
// func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
// let delete = UITableViewRowAction(style: .destructive, title: "Delete") { (action, indexPath) in
// // delete item at indexPath
// }
// let share = UITableViewRowAction(style: .normal, title: "Disable") { (action, indexPath) in
// // share item at indexPath
// }
//
// share.backgroundColor = UIColor.blue
//
// return [delete, share]
// }
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
return []
}
// Reload the table data when a change is made
// func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
// self.tableView.reloadData()
// }
/*
// Override to support conditional editing of the table view.
override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
// Return false if you do not want the specified item to be editable.
return true
}
*/
/*
// Override to support rearranging the table view.
override func tableView(tableView: UITableView, moveRowAtIndexPath fromIndexPath: NSIndexPath, toIndexPath: NSIndexPath) {
}
*/
/*
// Override to support conditional rearranging of the table view.
override func tableView(tableView: UITableView, canMoveRowAtIndexPath indexPath: NSIndexPath) -> Bool {
// Return false if you do not want the item to be re-orderable.
return true
}
*/
//Table view data source (end)
////////////////////////////////////////////////
}
I have already tried the following as well:
-didSelectRowAtIndexPath: not being called
How to detect Cell selection in UITableView - Swift
Push segue from UITableViewCell to ViewController in Swift
How to tap cell's buttons in UITableViewCell without actionning the cell's segue
is it possible to segue from a UITableViewCell on a UIView to another view
UITableView didSelectRowAt is not called iOS 10, but works for 9.3.5
The UITableViewCell does have UIView and multiple UITextFields, so I did make sure that User Interaction Enabled is unchecked for the UIView and UITextFields.
EDIT: I have also looked in the debugger navigator and can see that the CPU usage percentage increases when I tap a cell (). Maybe there is a way to step deeper and see why that tap doesn't then cause the didSelectRowAt indexPath to be triggered..?
Does anyone know what could possibly be causing didSelectRowAt indexPath to not be triggered when the cell is tapped?
I faced the same issue and found an answer that was applicable for me here. I had this code for keyboard dismiss in viewWillAppear:
self.view.addGestureRecognizer(UITapGestureRecognizer(target: self.view, action: #selector(UIView.endEditing(_:))))
After commenting this line tapping started to work! But now I will have to find better way for keyboard dismiss. :) Kindly check your exstensions, probably you used similar solution for keyboard dismiss.

tableview persisting cell image after reloading

I have a tableview with cells that when selected displays an image within the selected cell, this image then disappears when the cell is selected again, and so on. When i press a submit button the selected cells are remembered and the tableview reloads with new data. But when doing this all the new data loads but the selected cell image persists. I have tried calling tableView.reloadData() on the main queue but it still persists. The image also persists when i press the submit button several times.
Heres my code:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return currentQuestion.answers.count
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return tableView.frame.height/CGFloat(currentQuestion.answers.count)
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
setSelectedArray()
let cell: AnswersTableViewCell = tableView.dequeueReusableCell(withIdentifier: "answersTableViewCell") as! AnswersTableViewCell
let text = currentQuestion.answers[indexPath.row]
let isAnAnswer = currentQuestion.answerKeys[indexPath.row]
cell.answerTextLabel.text = text
cell.answerView.backgroundColor = UIColor.white.withAlphaComponent(0.5)
cell.contentView.sendSubview(toBack: cell.answerView)
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let cell: AnswersTableViewCell = tableView.cellForRow(at: indexPath) as? AnswersTableViewCell {
if cell.answerImageView.image == nil {
cell.answerImageView.image = UIImage(named: "paw.png")
selected[indexPath.row] = true
} else {
cell.answerImageView.image = nil
selected[indexPath.row] = false
}
}
}
#IBAction func submitButtonWasPressed() {
if questionNumber < questions.count - 1 {
questionNumber += 1
setCurrentQuestion()
self.answersTableView.reloadData()
self.view.setNeedsDisplay()
}
}
Any help would be great. Thanks
You need to set the image back to its correct value in cellForRow. Cells in your table are reused between calls to reloadData, and since you're not touching the imageView, it's keeping its previous value. Looks to me like you want:
cell.answerImageView.image = selected[indexPath.row] ? UIImage(named: "paw.png") : nil
inside of tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath).