CheckBox on tableview duplicating, Swift, iOS - ios

I have a tableView that when selected changes an image from one to another. This all works fine but when I select a tableCell it changes the image, but when I scroll it has also changed the image of another cell that I didn't select.
Below is my code.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "FeaturesCell") as! FeaturesCell
cell.featuresLabel.text = self.items[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
pickedFeatures.append(items[indexPath.row])
let cell = tableView.cellForRow(at: indexPath) as! FeaturesCell
cell.checkImage.image = #imageLiteral(resourceName: "tick-inside-circle")
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
pickedFeatures.remove(at: pickedFeatures.index(of: items[indexPath.row])!)
let cell = tableView.cellForRow(at: indexPath) as! FeaturesCell
cell.checkImage.image = #imageLiteral(resourceName: "No-tick-inside-circle")
}
If I use detqueureusable cell in the did select function then it just doesn't change the picture at all when selected.

You can use tableView.dequeueReusableCell(_), The problem is, you didn't maintain the status of the selected cells.
Example :
class viewController: UIVieWController, UITableViewDelegate, UITableViewDataSource {
var selectedCellList = [IndexPath]()
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "FeaturesCell") as! FeaturesCell
cell.featuresLabel.text = self.items[indexPath.row]
if let _ = selectedCellList.index(of: indexPath) {
// Cell selected, update check box image with tick mark
cell.checkImage.image = #imageLiteral(resourceName: "tick-inside-circle")
} else {
// Cell note selected, update check box image without tick mark
cell.checkImage.image = #imageLiteral(resourceName: "No-tick-inside-circle")
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
pickedFeatures.append(items[indexPath.row])
if let index = selectedCellList.index(of: indexPath) {
selectedCellList.remove(at: index)
} else {
selectedCellList.append(indexPath)
}
tableView .reloadRows(at: [indexPath], with: .automatic)
}
}

Related

UITableViewCell 3 Time Selected Change Background Color on Multiple Selection

I have 5 rows. Background color will change when 3 or more is selected.
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath)
let backgroundView = UIView()
backgroundView.backgroundColor = YOUR_COLOR_HERE
cell.selectedBackgroundView = backgroundView
return cell
}
These code change bacground color. But I want the background color to change when 3 or more is selected.
How can I do that?
First of all you should add configuration for both states, whether tableviewCell meets the isTapsEnough condition or not.
var numberOfTaps: Int = 0
var isTapsEnough: Bool { retrun numberOfTaps >= 3 }
func tap() {
self.numberOfTaps += 1
if self.isTapsEnough {
self.tableView.reloadData()
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.contentView.backgroundColor = self.isTapsEnough ? .yellow : .clear
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) -> UITableViewCell {
self.tap()
}
you can use this
var numberTaps = 0
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//code cell
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
if numberTaps == 3
{
cell.backgroundColor = .red
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) -> UITableViewCell {
numberTaps += 1
if numberTaps == 3
{
tableView.reloadData()
}
}
You can try with this example, although code syntax may be wrong.
var indexPaths: [IndexPath] = [IndexPath]()
func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
if tableView.indexPathsForSelectedRows?.contains(indexPath) ?? false {
tableView.deselectRow(at: indexPath, animated: true)
return nil
}
indexPaths.append(indexPath)
return indexPath
}
func tableView(_ tableView: UITableView, willDeselectRowAt indexPath: IndexPath) -> IndexPath? {
for (index, value) in indexPaths.enumerated() {
if value == indexPath {
indexPaths.remove(at: index)
}
}
return nil
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//code cell
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
if indexPaths.count >= 3
{
cell.backgroundColor = .red
}
return cell
}
Best way to make adjustments in the background color, etc is in willDisplayCell and observe indexPathsForSelectedRows:
(disclaimer: typed in browser, not tested in Xcode)
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
if tableView.indexPathsForSelectedRows.count >= 3 && tableView.indexPathsForSelectedRows.contains(indexPath) {
cell.backgroundColor = .red // or change the backgroundView color
}
else {
cell.backgroundColor = .clear // or whatever color you want
}
}
This will help you to start
var SelectedIndexpath = [IndexPath]()
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if SelectedIndexpath.contains(indexPath){
SelectedIndexpath.remove(at: SelectedIndexpath.index(of: indexPath)!)
}else{
SelectedIndexpath.append(indexPath)
}
tableView.reloadData()
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
if SelectedIndexpath.count >= 3 && SelectedIndexpath.contains(indexPath){
cell.backgroundColor = .red
}else{
cell.backgroundColor = .white
}
cell.accessoryType = SelectedIndexpath.contains(indexPath) ? .checkmark : .none
cell.textLabel?.text = "\(indexPath.row)"
return cell
}

present UITableViewController the door cell TableViewController?

I want SelectRow open tableview without storyboard ??
tableview without storyboard
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.row == 3 {
let main = UITableViewController()
let color = UIColor.yellow
main.view.backgroundColor = color
self.present(main, animated: true)
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath)
let name = twoDimensionalArray[indexPath.section][indexPath.row]
return cell
}
You shouldn't nest the functions
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.row == 3 {
let main = UITableViewController()
let color = UIColor.yellow
main.view.backgroundColor = color
self.present(main, animated: true)
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath)
let name = twoDimensionalArray[indexPath.section][indexPath.row]
// use name here
return cell
}

How to Access cell imageView from didSelectRowAtindexPath: function

Im trying to use core animation for an UIImageView in a cell. Im not sure how to access the cell or the UIImageView.
Im using swift 5.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as! CountryListCell
cell.accessoryType = .disclosureIndicator
let str = factsJsonList[indexPath.row].country
let image = UIImage(named: str)
cell.flagImageView.image = image
cell.flagNameLabel.text = str.uppercased()
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = [tableView.cellForRow(at: indexPath)]
// TODO :core animate the image view
let vc = CountryFactListVC()
vc.country = factsJsonList[indexPath.row]
navigationController?.pushViewController(vc, animated: true)
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
//access the current cell
guard let cell = tableView.cellForRow(at: indexPath) as? CountryListCell
else{
return
}
// TODO :core animate the image view
let imageViewToAnimate = cell.flagImageView //you can use this object to animate image view of cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
//access the current cell
guard let cell = tableView.cellForRow(at: indexPath) as? CountryListCell else{
return
}
// TODO :core animate the image view
let vc = CountryFactListVC()
vc.country = factsJsonList[indexPath.row]
navigationController?.pushViewController(vc, animated: true)
}

Not Recognizing Clicked Cell UITableView inside UITableViewCell using NIB

I'm writing an app that have a dashboard with multiple cells. One of the cells have a question, but the answer are dynamically filled, so I decided to use a UITableView to handle it.
I set the the UITableViewCell as the delegate and dataSource of the internal UITableView and made the configurations for define the cell and the selected state.
extension SurveyTableViewCell: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
answers = model.getSurveyAnswers()
return (answers?.count)!
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: InsideSurveyTableViewCell.identifier, for: indexPath) as! InsideSurveyTableViewCell
cell.idAnswer.text = alphabetQuestion[indexPath.row]
cell.answer.text = answers?[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return 100.0
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.dequeueReusableCell(withIdentifier: InsideSurveyTableViewCell.identifier, for: indexPath) as! InsideSurveyTableViewCell
cell.selectRow()
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
let cell = tableView.dequeueReusableCell(withIdentifier: InsideSurveyTableViewCell.identifier, for: indexPath) as! InsideSurveyTableViewCell
cell.deselectRow()
}
}
But the click inside the cell in the internal UITableViewCell is not recognized. I need to recognize this click to after send the user answer to the server.
I saw some solutions, but using storyboard. I use only nib's on my projects.
But I still tried with an approach that I saw on youtube wich uses storyboard.
On the cell that will use the internal UITableView I declared a function to set the delegate and dataSource of the internal tableView and gave to it a tag.
extension SurveyTableViewCell {
func setTableViewDataSourceDelegate<D:UITableViewDelegate & UITableViewDataSource>(_ dataSourceDelegate: D, forRow row: Int) {
subTableView.dataSource = dataSourceDelegate
subTableView.delegate = dataSourceDelegate
subTableView.reloadData()
}
}
Than on the viewController that manage the outer UITableView:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if tableView.tag == 1 {
let cell = tableView.dequeueReusableCell(withIdentifier: InsideSurveyTableViewCell.identifier) as! InsideSurveyTableViewCell
cell.idAnswer.text = "A."
cell.answer.text = "QUALQUER COISA"
return cell
}
if retrivedCell is SurveyTableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: SurveyTableViewCell.identifier, for: indexPath) as! SurveyTableViewCell
cell.delegate = self
cell.setTableViewDataSourceDelegate(self, forRow: indexPath.row)
cell.setPositionRow(row: indexPath.row - 1)
cell.subTableView.rowHeight = UITableViewAutomaticDimension
cell.subTableView.estimatedRowHeight = 50
return cell
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if tableView.tag == 1 {
return 3
}
var numberOfCells: Int = 0
if cellsToPresent != nil {
numberOfCells = cellsToPresent!.count
}
return numberOfCells + 1
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if tableView.tag == 1 {
let cell = tableView.dequeueReusableCell(withIdentifier: InsideSurveyTableViewCell.identifier) as! InsideSurveyTableViewCell
cell.selectRow()
}
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
if tableView.tag == 1 {
let cell = tableView.dequeueReusableCell(withIdentifier: InsideSurveyTableViewCell.identifier) as! InsideSurveyTableViewCell
cell.deselectRow()
}
}
The selectRow and deselectRow are methods to change the label of the cell of the inner tableView.
But still without success.
if I use the method:
tableView.dequeueReusableCell(withIdentifier: identifier, for: indexPath)
The app break complaining that I'm trying to dequeue different cells with the same indexPath.
Thanks for your help.
Don't use
let cell = tableView.dequeueReusableCell(withIdentifier:) in didSelect or didDeSelect methods.
Use
let cell = tableView.cellForRow(at: indexPath)
I hope this will help you.

UITableView cell on double click should go to previous state

If I select (click) row of TableView, it should add Image saying that I selected this particular Item. It's working fine!
My problem is: if user want to move back from that selected item.
If I click on the same row it should deselect that cell and hide that image.
What I tried is:
func tableView (_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tableData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath as IndexPath) as! leistungCell
// Configure the cell...
let tableData = self.tableData[indexPath.row]
cell.leistungLbl.text = tableData["leistung_info"] as? String
//space between Rows
cell.contentView.backgroundColor = colorLightGray
cell.contentView.layer.borderColor = UIColor.white.cgColor
//space between Rows
cell.contentView.layer.borderWidth = 3.0
cell.contentView.layer.cornerRadius = 8
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath)
cell?.imageView?.image = UIImage(named: "check.png")
let value = Info["leistung_info"] as! String
}
func tableView(_ tableView: UITableView, didDeSelectRowAt indexPath: IndexPath){
let cell = tableView.cellForRow(at: indexPath)
cell?.imageView?.image = nil
}
Forget and remove didDeSelectRowAt, just use didSelectRowAt, and an array to save selections:
var selectedIndexPaths = [IndexPath]()
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath)
if let index = selectedIndexPaths.index(of: indexPath) { //deselect it if the row is selected
tableView.deselectRow(at: indexPath, animated: true)
cell?.imageView?.image = nil
selectedIndexPaths.remove(at: index)
}
else{ //select it if the row is deselected
cell?.imageView?.image = UIImage(named: "check.png")
selectedIndexPaths.append(indexPath)
}
}
And be aware of that the cells are being REUSED ! Please do the same check in cellForRowAt method.

Resources