考虑以下内置断言:
button.isSelected = true
button.setImage(nil, for: .selected)
assert(button.image(for: .selected) === nil)
//^^^^^^^^^^^^^^ this trips with === and ==
为什么?我是否做出了无效的假设?
来自苹果的文档:
讨论
将图像关联到按钮时,至少应设置正常状态的图像。如果您没有为其他状态指定图像,则该按钮将使用与正常关联的图像。如果您没有指定正常状态的图像,则该按钮将使用系统值。
可能不太清楚的是,调用:
button.setImage(nil, for: .selected)
也可以理解为:“没有为
.selected
状态指定图像。”
因此,该按钮将使用来自
.normal
的图像。
如果您想在将按钮状态设置为.selected
时
删除图像:
button.isSelected = true
button.setImage(nil, for: .normal)
button.setImage(nil, for: .selected)
这里有一些示例代码可供使用:
class SelectedButtonVC: UIViewController {
let button = UIButton()
var toggles: [UISwitch] = []
var imgs: [String : UIImage] = [:]
let titles: [String] = [
"Normal", "Highlighted", "Selected",
]
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBackground
var promptLabel: UILabel!
var vSep: UIView!
var hs: UIStackView!
let stack = UIStackView()
stack.axis = .vertical
stack.spacing = 8
let colors: [UIColor] = [
.systemBlue, .systemRed, .systemGreen,
]
let states: [UIControl.State] = [
.normal, .highlighted, .selected,
]
let largeConfig = UIImage.SymbolConfiguration(pointSize: 40, weight: .bold, scale: .large)
for (t, c) in zip(titles, colors) {
guard let f = t.first?.description else { fatalError() }
guard let img = UIImage(systemName: "\(f.lowercased()).square.fill", withConfiguration: largeConfig)?.withTintColor(c, renderingMode: .alwaysOriginal) else {
fatalError("Could not load system image for \(t.lowercased())")
}
imgs[t] = img
}
for (t, s) in zip(titles, states) {
button.setTitle(t, for: s)
button.setImage(imgs[t], for: s)
}
for (c, s) in zip(colors, states) {
button.setTitleColor(c, for: s)
}
button.backgroundColor = UIColor(white: 0.9, alpha: 1.0)
button.layer.cornerRadius = 8
button.layer.borderWidth = 1
promptLabel = UILabel()
promptLabel.text = "This is a button..."
stack.addArrangedSubview(promptLabel)
stack.addArrangedSubview(button)
stack.setCustomSpacing(20.0, after: button)
vSep = UIView()
vSep.backgroundColor = .gray
vSep.heightAnchor.constraint(equalToConstant: 2.0).isActive = true
stack.addArrangedSubview(vSep)
hs = UIStackView()
hs.spacing = 8
hs.alignment = .center
promptLabel = UILabel()
promptLabel.text = "Toggle button.isSelected:"
hs.addArrangedSubview(promptLabel)
let sw = UISwitch()
sw.isOn = false
toggles.append(sw)
hs.addArrangedSubview(sw)
stack.addArrangedSubview(hs)
vSep = UIView()
vSep.backgroundColor = .gray
vSep.heightAnchor.constraint(equalToConstant: 2.0).isActive = true
stack.addArrangedSubview(vSep)
stack.setCustomSpacing(20.0, after: vSep)
promptLabel = UILabel()
promptLabel.text = "Toggle button images for states:"
stack.addArrangedSubview(promptLabel)
titles.forEach { t in
hs = UIStackView()
hs.spacing = 8
hs.alignment = .center
promptLabel = UILabel()
promptLabel.text = t
hs.addArrangedSubview(promptLabel)
let v = UIImageView(image: imgs[t])
v.contentMode = .scaleAspectFit
v.heightAnchor.constraint(equalTo: v.widthAnchor).isActive = true
hs.addArrangedSubview(v)
let sw = UISwitch()
sw.isOn = true
toggles.append(sw)
hs.addArrangedSubview(sw)
stack.addArrangedSubview(hs)
}
stack.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(stack)
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
stack.topAnchor.constraint(equalTo: g.topAnchor, constant: 40.0),
stack.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 40.0),
stack.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -40.0),
button.heightAnchor.constraint(equalToConstant: 60.0),
])
toggles.forEach { sw in
sw.addTarget(self, action: #selector(swTapped(_:)), for: .valueChanged)
}
button.addTarget(self, action: #selector(btnTapped(_:)), for: .touchUpInside)
}
@objc func swTapped(_ sender: UISwitch) {
guard let idx = toggles.firstIndex(of: sender) else { return }
switch idx {
case 1:
button.setImage(sender.isOn ? imgs[titles[0]] : nil, for: .normal)
()
case 2:
button.setImage(sender.isOn ? imgs[titles[1]] : nil, for: .highlighted)
()
case 3:
button.setImage(sender.isOn ? imgs[titles[2]] : nil, for: .selected)
()
default:
button.isSelected = sender.isOn
()
}
}
@objc func btnTapped(_ sender: UIButton) {
print("button.isSelected =", sender.isSelected)
}
}
看起来像这样:
运行时,切换
.isSelected
开关,正如您可能猜到的那样,将 button.isSelected
设置为 true
或 false
。
切换按钮图像状态开关会将图像设置为图像(如果打开)或将其设置为
nil
(如果关闭)。
也许值得注意...
当按钮有:
btn.isSelected = true
正常属性(标题、标题颜色、图像等)用于突出显示状态。
可以在上面的示例代码中看到这一点,方法是将
.isSelected
切换为“开”,然后点击该按钮。我们不再看到“突出显示”的标题或图像。
如果这是您的预期行为,那就太好了!如果没有,您可能需要重新考虑您的方法。