Reputation: 145
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)
Upvotes: 1
Views: 2257
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
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
}
}
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
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