EDIT: Using the configuration method from the accepted answer fixed the problem. Setting the title with setTitle would be simpler, but isn't possible since it has to be an attributed string.
In a project I'm working on currently, there is a UITableView which gets its cells from a custom class. Inside each cell is a label and a button. I set default values for the text/fonts of both of these elements in the custom class' .xib file, and then override the values at runtime (the reason for doing this is to scale the sizes and spacing of all UI elements to fit on any size device screen, when the current device isn't known until runtime).
The label works as I intended, and keeps the new value which is assigned programmatically. The problem is that the button doesn't. Its text starts out showing the new value, but then defaults back to the old Storyboard value as soon as it's clicked, and won't go back to the runtime value. I don't want the placeholder value to ever show, only the value I set in the setLabelValues function.
Here is the code which is causing the problem (a minimal reproducible example, not the original program, but it is exhibiting the exact same problem):
CUSTOM TABLE VIEW CELL:
import UIKit
class testCellTableViewCell: UITableViewCell {
@IBOutlet weak var textLabelLeading: NSLayoutConstraint!
@IBOutlet weak var textLabelTrailing: NSLayoutConstraint!
@IBOutlet weak var buttonLabelLeading: NSLayoutConstraint!
@IBOutlet weak var buttonLabelTrailing: NSLayoutConstraint!
@IBOutlet weak var workingCorrectlyLabel: UILabel!
@IBOutlet weak var buggyButton: UIButton!
override func awakeFromNib() {
super.awakeFromNib()
}
func setLabelValues(screenWidth: CGFloat, screenHeight: CGFloat) {
textLabelLeading.constant = 0.025 * screenWidth
textLabelTrailing.constant = -0.4 * screenWidth
buttonLabelLeading.constant = 0.6 * screenWidth
buttonLabelTrailing.constant = -0.025 * screenWidth
workingCorrectlyLabel.font = UIFont.systemFont(ofSize: 0.025*screenHeight, weight: .regular)
buggyButton.titleLabel?.text = "Fixed!"
buggyButton.titleLabel?.textColor = .green
buggyButton.titleLabel?.font = UIFont.systemFont(ofSize: 0.025*screenHeight, weight: .medium)
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
}
VIEW CONTROLLER:
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var testTable: UITableView!
var labelMessages = ["This is a test", "Second Cell", "Another Label"]
override func viewDidLoad() {
super.viewDidLoad()
testTable.dataSource = self
testTable.register(UINib(nibName: "testCellTableViewCell", bundle: nil), forCellReuseIdentifier: "testCellID")
testTable.layoutMargins = UIEdgeInsets.zero
testTable.separatorInset = UIEdgeInsets.zero
}
}
extension ViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
tableView.layer.backgroundColor = CGColor(red: 0.000, green: 0.000, blue: 0.000, alpha: 1.000)
return labelMessages.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = testTable.dequeueReusableCell(withIdentifier: "testCellID", for: indexPath) as! testCellTableViewCell
cell.workingCorrectlyLabel.text = labelMessages[indexPath.row]
cell.layoutMargins = UIEdgeInsets.zero
cell.setLabelValues(screenWidth: view.safeAreaLayoutGuide.layoutFrame.width, screenHeight: view.safeAreaLayoutGuide.layoutFrame.height)
return cell
}
}
And here is a picture of the .xib file storyboard, showing the default values. Picture of Xcode window showing xib file and attributes inspector. The default text for the button is the string "Buggy" in the system red color.
CodePudding user response:
Another way to set button values is by using its configuration. It gives you more control over the button properties by using it's state, instead of accessing the titleLabel directly
Example:
func setLabelValues(screenWidth: CGFloat, screenHeight: CGFloat) {
textLabelLeading.constant = 0.025 * screenWidth
textLabelTrailing.constant = -0.4 * screenWidth
buttonLabelLeading.constant = 0.6 * screenWidth
buttonLabelTrailing.constant = -0.025 * screenWidth
workingCorrectlyLabel.font = UIFont.systemFont(ofSize: 0.025*screenHeight, weight: .regular)
// Original way
buggyButton.titleLabel?.text = "Fixed!"
buggyButton.titleLabel?.textColor = .green
buggyButton.titleLabel?.font = UIFont.systemFont(ofSize: 0.025*screenHeight, weight: .medium)
// Configuration way
// this is for the attributed title to set on the button later
var container = AttributeContainer()
container.font = UIFont.systemFont(ofSize: 0.025*screenHeight, weight: .medium)
buggyButton.configurationUpdateHandler = { button in
switch button.state {
// you can switch over the different button states here, but i'll use default to make all button states the same
default:
button.configuration = .plain() // or .filled() or .tinted() whatever you prefer
button.configuration?.attributedTitle = AttributedString("Fixed", attributes: container)
button.configuration?.baseForegroundColor = .green
}
You can also just set the title of the button using setTitle method of the button:
buggyButton.setTitle("Fixed", for: .normal)
See if this way gives you any issues...