How to change Button color in specific TableViewCell

I have an app like a quiz app. In tableViewCell there are 4 buttons for variants of the task. And I need to change color when the user is pressed the button, when I try to just change color in action of button the color of button changes in all table view Cells. But I need to change only in that, where I pressed. I already tried to write delegate, But it is giving the same result this is code how I wrote my delegate:

class CustomButton: UIButton {

override var isHighlighted: Bool {
    didSet {
        if isHighlighted {
            backgroundColor = UIColor.lightGray
        } else {
            backgroundColor = UIColor.init(red: 34/255, green: 89/255, blue: 128/255, alpha: 1.0)
        }
    }
}

}

I already have added target actions to buttons.

var variant1 = UIButton()
var variant2 = UIButton()
var variant3 = UIButton()
var variant4 = UIButton()

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "finalCell")!
    variant1 = cell.contentView.viewWithTag(1) as! UIButton
    variant2 = cell.contentView.viewWithTag(2) as! UIButton
    variant3 = cell.contentView.viewWithTag(3) as! UIButton
    variant4 = cell.contentView.viewWithTag(4) as! UIButton


    if (numberOfVariants.count != 0) {
        let questionTextView = cell.contentView.viewWithTag(5) as! UITextView
        questionTextView.text = "\(Questions[indexPath.row].content!)"
        variant1.addTarget(self, action: #selector(self.variant1ButtonPressed), for: .touchUpInside)
        variant2.addTarget(self, action: #selector(self.variant2ButtonPressed), for: .touchUpInside)
        variant3.addTarget(self, action: #selector(self.variant3ButtonPressed), for: .touchUpInside)
        variant4.addTarget(self, action: #selector(self.variant4ButtonPressed), for: .touchUpInside)
          }
        return cell
    }

I already identified the indexPath of table view (if it is helpful), when the user clicked to button:

    func variant1ButtonPressed(_ sender:AnyObject) {
    print("Variant1")
    let buttonPosition:CGPoint = sender.convert(CGPoint.zero, to:self.tableView)
    let indexPath = self.tableView.indexPathForRow(at: buttonPosition)
    let intIndexpath = Int((indexPath?.row)!)
    globalIndexPath = intIndexpath
}
func variant2ButtonPressed(_ sender:AnyObject) {
    let buttonPosition:CGPoint = sender.convert(CGPoint.zero, to:self.tableView)
    let indexPath = self.tableView.indexPathForRow(at: buttonPosition)
    let intIndexpath = Int((indexPath?.row)!)
    globalIndexPath = intIndexpath

}
func variant3ButtonPressed(_ sender:AnyObject) {
    let buttonPosition:CGPoint = sender.convert(CGPoint.zero, to:self.tableView)
    let indexPath = self.tableView.indexPathForRow(at: buttonPosition)
    let intIndexpath = Int((indexPath?.row)!)
    globalIndexPath = intIndexpath


}
func variant4ButtonPressed(_ sender:AnyObject) {
    let buttonPosition:CGPoint = sender.convert(CGPoint.zero, to:self.tableView)
    let indexPath = self.tableView.indexPathForRow(at: buttonPosition)
    let intIndexpath = Int((indexPath?.row)!)
    globalIndexPath = intIndexpath


}

This how its looks like in storyboard(If it is helpful) enter image description here

Upvotes: 1

Views: 2257

Answers (2)

Reinier Melian
Reinier Melian

Reputation: 20804

I think you are using much more code than you really need to do this task, so this is another approach using closures, I have only one viewController in my storyboard and add a UITableView inside and a customCell called ButtonTableViewCell then I linked a normal UIButton to that cell as @IBOutlet and that is all, the full implementation is here

https://github.com/rmelian2014/SOButtonsTableViewCellQuestion

EDITED

ButtonTableViewCell

    import UIKit

@IBDesignable
class ButtonTableViewCell: UITableViewCell {

    @IBInspectable var selectedColor : UIColor = UIColor.red
    @IBInspectable var normalColor : UIColor = UIColor.blue

    static let cellHeigth : CGFloat = 360

    @IBOutlet var buttonsArray: [UIButton]!
    var selectedText : String?{
        willSet{
            guard newValue != nil else{
                return
            }

            var foundedIndex = -1
            for (index,text) in self.texts.enumerated() {
                if(text == newValue!){
                    foundedIndex = index
                    break
                }
            }

            guard foundedIndex != -1 else
            {
                return
            }

            self.buttonsArray[foundedIndex].backgroundColor = selectedColor
        }
    }
    var texts : [String] = []

    var buttonActionClosure : ((_ selectedText:String?)->Void)?

    func setupWithClosure(texts:[String],textSelected:String?,closure:((_ selectedText:String?)->Void)?)
    {
        self.texts = texts

        for (index,button) in self.buttonsArray.enumerated(){
            if(self.texts.count > index)
            {
                button.setTitle(self.texts[index], for: .normal)
            }
            button.tag = index
            button.backgroundColor = self.normalColor
        }


        self.selectedText = textSelected
        if(closure != nil)
        {
            self.buttonActionClosure = closure
        }


    }

    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
    }

    @IBAction func buttonAction(sender:UIButton)
    {
        if(self.texts.count > sender.tag){
            let newSelectedText = self.texts[sender.tag]

            if(newSelectedText != self.selectedText){
                self.selectedText = newSelectedText
            }else
            {
                self.selectedText = nil
            }
        }
        if(self.buttonActionClosure != nil)
        {
            self.buttonActionClosure!(self.selectedText)
        }
    }

    override func prepareForReuse() {
        super.prepareForReuse()
        self.buttonActionClosure = nil
    }

}

ViewController

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var tableView: UITableView!

    var dictOfSelectedsCells : [Int:String?] = [:]

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        tableView.delegate = self
        tableView.dataSource = self
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


}

extension ViewController : UITableViewDelegate,UITableViewDataSource
{
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 4
    }

    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return ButtonTableViewCell.cellHeigth
    }

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

        if let cell = tableView.dequeueReusableCell(withIdentifier: "ButtonTableViewCell", for: indexPath) as? ButtonTableViewCell
        {
            cell.selectionStyle = .none
            var selectedText : String?
            if let currentSelectedText = self.dictOfSelectedsCells[indexPath.row]
            {
                selectedText = currentSelectedText
            }

            cell.setupWithClosure(texts:["Variant1","Variant2","Variant3","Variant4"], textSelected: selectedText, closure: { [weak self] (selected) in
                debugPrint(indexPath)
                self?.dictOfSelectedsCells[indexPath.row] = selected
                tableView.reloadRows(at: [indexPath], with: .none)
            })

            return cell
        }
        assert(false, "this must not happen")
    }
}

Hope this helps you

Upvotes: 2

Kapil G
Kapil G

Reputation: 4141

In your cellForRowAt indexPath: method you need to check if the indexpath of the row is same as the indexpath of the selected button. if its same then you need to show the highlighted color otherwise the normal color.

so save the indexpath of the button pressed in a global variable in your buttonpressedmethod. let the valiable be selectedButtonIndexPath.

Add below code in your cellForRowAt indexPath: method

 if indexPath.row==selectedButtonIndexPath.row {
        backgroundColor = UIColor.lightGray
    } else {
        backgroundColor = UIColor.init(red: 34/255, green: 89/255, blue: 128/255, alpha: 1.0)
    }

And ofcourse reload your tableview when a button is clicked to reflect the change in the color.

Update 1:

Can you try saving the tag of the button as well in your button pressed methods by getting sender.tag and then change your if condition

if indexPath.row==selectedButtonIndexPath.row  {
    if buttonTag == 1{
        variant1.backgroundcolor = UIColor.lightGray
        variant2.backgroundColor = UIColor.init(red: 34/255, green: 89/255, blue: 128/255, alpha: 1.0)
        // and so on for all buttons.
    }else if buttonTag == 2{
        // same as above but for variant2
    }
} else {

}

Upvotes: 0

Related Questions