为什么 UITableViewCells 中的 UIButtons 会丢失它们在运行时设置的值并默认返回到它们的 Interface Builder 值?
Why do UIButtons inside UITableViewCells lose their values which were set at runtime and default back to their Interface Builder values?
编辑:使用已接受答案中的配置方法解决了问题。使用 setTitle 设置标题会更简单,但不可能,因为它必须是属性字符串。
在我目前正在处理的项目中,有一个 UITableView 从自定义 class 获取其单元格。每个单元格内都有一个标签和一个按钮。我在自定义 class' .xib 文件中为这两个元素的 text/fonts 设置默认值,然后在运行时覆盖这些值(这样做的原因是为了缩放尺寸和间距所有 UI 元素都适合任何尺寸的设备屏幕,当前设备直到运行时才知道)。
标签按我的预期工作,并保留以编程方式分配的新值。问题是按钮没有。它的文本开始显示新值,但一旦单击它就会默认返回到旧的 Storyboard 值,并且不会返回到运行时值。我不想显示占位符值,只显示我在 setLabelValues 函数中设置的值。
这是导致问题的代码(一个最小的可重现示例,不是原始程序,但它表现出完全相同的问题):
自定义 TABLE 查看单元格:
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)
}
}
查看控制器:
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
}
}
这里是 .xib 文件故事板的图片,显示了默认值。 Xcode window 的图片显示了 xib 文件和属性检查器。按钮的默认文本是系统红色的字符串“Buggy”。
另一种设置按钮值的方法是使用它的配置。它使您可以通过使用它的状态来更好地控制按钮属性,而不是直接访问 titleLabel
示例:
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
}
您也可以使用按钮的 setTitle 方法只设置按钮的标题:
buggyButton.setTitle("Fixed", for: .normal)
看看这种方式是否会给您带来任何问题...
编辑:使用已接受答案中的配置方法解决了问题。使用 setTitle 设置标题会更简单,但不可能,因为它必须是属性字符串。
在我目前正在处理的项目中,有一个 UITableView 从自定义 class 获取其单元格。每个单元格内都有一个标签和一个按钮。我在自定义 class' .xib 文件中为这两个元素的 text/fonts 设置默认值,然后在运行时覆盖这些值(这样做的原因是为了缩放尺寸和间距所有 UI 元素都适合任何尺寸的设备屏幕,当前设备直到运行时才知道)。
标签按我的预期工作,并保留以编程方式分配的新值。问题是按钮没有。它的文本开始显示新值,但一旦单击它就会默认返回到旧的 Storyboard 值,并且不会返回到运行时值。我不想显示占位符值,只显示我在 setLabelValues 函数中设置的值。
这是导致问题的代码(一个最小的可重现示例,不是原始程序,但它表现出完全相同的问题):
自定义 TABLE 查看单元格:
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)
}
}
查看控制器:
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
}
}
这里是 .xib 文件故事板的图片,显示了默认值。 Xcode window 的图片显示了 xib 文件和属性检查器。按钮的默认文本是系统红色的字符串“Buggy”。
另一种设置按钮值的方法是使用它的配置。它使您可以通过使用它的状态来更好地控制按钮属性,而不是直接访问 titleLabel
示例:
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
}
您也可以使用按钮的 setTitle 方法只设置按钮的标题:
buggyButton.setTitle("Fixed", for: .normal)
看看这种方式是否会给您带来任何问题...