2

I have a UICollectionView.

Inside each UICollectionViewCell of UICollectionView, I have a UITableView.

Inside each UITableViewCell of UITableView, I have a UIButton.

When clicking on UIButton or UITableViewCell, I want to change the image of UIButton.

Here is my UICollectionView:

enter image description here

Here is my code:

SurveyQuestionsCollectionViewController.swift

import UIKit

class SurveyQuestionCollectionViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate  {

    var survey_questions: [Dictionary<String, Any>] = []

    @IBOutlet weak var collectionView: UICollectionView!

    override func viewDidLoad() {
        super.viewDidLoad()

        self.collectionView?.register(UINib.init(nibName: "SurveyQuestionsCollectionViewCell", bundle: nil), forCellWithReuseIdentifier: "survey_cell")

        let layout = self.collectionView?.collectionViewLayout as! UICollectionViewFlowLayout
        let collectionViewSize = self.collectionView?.frame.size
        let itemWidth = Int((collectionViewSize?.width)!)
        let itemHeight = Int((collectionViewSize?.height)!)
        layout.itemSize = CGSize(width: itemWidth, height: itemHeight)

        common()

        //result is coming from API call which I have deleted as it is not necessary to describe my problem
        self.survey_questions = result["survey_questions"] as! [Dictionary<String, Any>]

        self.collectionView?.reloadData()

    }

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        common()
        return survey_questions.count
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

        var question = survey_questions[indexPath.item]

        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "survey_cell", for: indexPath) as! SurveyQuestionsCollectionViewCell

        cell.setValues(question: question["question"]! as! String,
                       answers: question["answers"]! as! [Dictionary<String, Any>])

        return cell
    }

    func common() {

        self.collectionView.setContentOffset(CGPoint(x: CGFloat(currentPosition) * self.collectionView.frame.size.width, y: 0), animated: true)

    }

}

Here is my UICollectionViewCell and UITableView:

enter image description here

SurveyQuestionsCollectionViewCell.swift (at the back of .xib file)

import UIKit

class SurveyQuestionsCollectionViewCell: UICollectionViewCell, UITableViewDataSource, UITableViewDelegate {

    var answers: [Dictionary<String, Any>] = []

    @IBOutlet weak var questionLabel: UILabel!

    @IBOutlet weak var tableView: UITableView!

    override func layoutSubviews() {
        super.layoutSubviews()
        self.tableView.delegate = self
        self.tableView.dataSource = self

        self.tableView?.register(UINib.init(nibName: "SurveyQuestionsTableViewCell", bundle: nil), forCellReuseIdentifier: "survey_answer_cell")
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return answers.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        let answer = answers[indexPath.row]

        let cell = tableView.dequeueReusableCell(withIdentifier: "survey_answer_cell", for: indexPath) as! SurveyQuestionsTableViewCell

        cell.setRadioText(text: answer["answer"]! as! String)

        return cell

    }

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

        let cell = tableView.dequeueReusableCell(withIdentifier: "survey_answer_cell", for: indexPath) as! SurveyQuestionsTableViewCell

        cell.setRadioImage(rowSelected: true, tableView: tableView)

    }

    func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {

        let cell = tableView.dequeueReusableCell(withIdentifier: "survey_answer_cell", for: indexPath) as! SurveyQuestionsTableViewCell

        cell.setRadioImage(rowSelected: false, tableView: tableView)

    }

    func setValues(question: String, answers: [Dictionary<String, Any>]) {
        self.questionLabel.text = question
        self.answers = answers
        self.tableView.reloadData()
    }

}

Here is my TableViewCell

enter image description here

enter image description here

SurveyQuestionsTableViewCell.swift (at the back of .xib file)

import UIKit

class SurveyQuestionsTableViewCell: UITableViewCell {

    @IBOutlet weak var radioButton: UIButton!

    @IBOutlet weak var radioLabel: UILabel!

    func setRadioText(text: String) {
        radioLabel.text = text
    }

    func setRadioImage(rowSelected: Bool, tableView: UITableView) {
        if rowSelected {
            if let image = UIImage(named: "radioOn") as UIImage! {
                    self.radioButton.setImage(image, for: UIControlState.normal)
                }
            }
        } else {
            if let image = UIImage(named: "radioOff") as UIImage! {
                    self.radioButton.setImage(image, for: UIControlState.normal)
                }
        }
    }
}

And here is my output:

enter image description here

Every time when I click on any TableCell, I would like to change the image of radioButton. But the image is not changing. I have also marked that code for changing image is executed but the image is not changing.

Vishal
  • 6,238
  • 10
  • 82
  • 158
  • Check your button's outlet is proper ? – iPatel Oct 10 '17 at 09:52
  • @iPatel you its good. – Vishal Oct 10 '17 at 09:52
  • Make Datasource handle the checking and unchecking behavior. Make is selected Bool variable. and on cellfor row at index path set image according to that variable of datasource. simply on didSelect method change Value of that variable of the specific index then reload the table vie. – dip Oct 10 '17 at 10:06

2 Answers2

2

It's happening because you set cell.setRadioImage(rowSelected: false, tableView: tableView) code indidDeselectRowAtmethod look at your below code

func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {

    let cell = tableView.dequeueReusableCell(withIdentifier: "survey_answer_cell", for: indexPath) as! SurveyQuestionsTableViewCell

    cell.setRadioImage(rowSelected: false, tableView: tableView)

}

Just remove last line.

Updated :

For get cell in tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) you need write below line

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    tableView.deselectRow(at: indexPath, animated: true)
    // Your Stuff 

    let cell = tableView.cellForRow(at: indexPath) // Change this line

   // Your Stuff 
}
iPatel
  • 46,010
  • 16
  • 115
  • 137
  • Thanks for the answer. I have tried that right now, but still no change in output. – Vishal Oct 10 '17 at 10:00
  • In didSelectRow... method use let cell = self.tableView.cellForRowAtIndexPath(indexPath) for get cell – iPatel Oct 10 '17 at 10:01
  • Thanks man! that is working fine now. Can you please explain me the above mentioned line? – Vishal Oct 10 '17 at 10:07
  • If you want to get selected cell in didSelectRowAtIndexPath method then you can get it by above code. – iPatel Oct 10 '17 at 10:10
  • Jay Girnari proper junagadh? apdu Talala Gir – iPatel Oct 10 '17 at 10:11
  • Above answer does not resolve the problem if there are big numbers of options. – dip Oct 10 '17 at 10:13
  • Jay Girnari bhai, I am also Patel – Vishal Oct 10 '17 at 10:14
  • @dip why? can you please explain me? – Vishal Oct 10 '17 at 10:14
  • When you scroll large set of answer the datasource method of table view will ask for new cell be dequeued. And there is no any mechanism to control at that point as per your answer. Indeed it will work for few numbers of answers. but if user scrolls on options then i am sure it will fail. – dip Oct 10 '17 at 10:17
  • @Vishal dip is right If you will get issue like when you scroll up/down and your selected button will change image then you can follow this logic https://stackoverflow.com/questions/45954700/how-to-change-the-button-title-on-click-inside-a-tableview-cell-in-swift-3/45954991#45954991 – iPatel Oct 10 '17 at 10:24
  • @dip So, can you please provide a nice and clean solution which will not fail even if user scrolls when there is a big no. of items? – Vishal Oct 10 '17 at 10:24
  • @Vishal for check it. Take 50 row -> select some button -> scroll up and down table view? and see selected button is remove it's image or not ? I think you do not apply this logic just check and let me know – iPatel Oct 10 '17 at 10:26
  • Ok I will check it and let you know if the problem persists. I will also check the link given by you – Vishal Oct 10 '17 at 10:28
2

Instead of doing that much, follow the below step and do in short and clear.

  1. Select your button and assign the image for its state.

a. for Default State

enter image description here

b. for Selected State

enter image description here

  1. In SurveyQuestionsCollectionViewCell

    var indexSelected : Int = 0

  2. In cellForRowAt

      if indexPath.row == indexSelected{
             cell.button.isSelected = true
      }
      else{
             cell.button.isSelected = false
     }
    
  3. in didSelectRowAt

      self.indexSelected = indexPath.row
      table.reloadData()
    

If still facing any issue then ask.

dahiya_boy
  • 9,298
  • 1
  • 30
  • 51