Swift: UIButton 不可点击,NSLayoutConstraint heightAnchor 问题
Swift: UIButton not clickable, NSLayoutConstraint heightAnchor issues
我正在构建一个简单的刽子手游戏。
我用 UIButtons 构建了一个简单的键盘。键盘在子视图内,每一行都是一个单独的子视图。
按钮不可点击,我可以让顶行工作,但其他行被推开。
我已经尝试设置 NSLayoutConstraint 高度锚点,它会将 UIButton 推出相应的视图。
class ViewController: UIViewController {
// letterGuess
// usedLetters
// score/lives
var scoreLabel: UILabel!
var answerLabel: UILabel!
var characterButtons = [UIButton]()
var score = 0 {
didSet {
scoreLabel.text = "Score: \(score)"
}
}
override func loadView() {
view = UIView()
view.backgroundColor = .white
scoreLabel = UILabel()
scoreLabel.translatesAutoresizingMaskIntoConstraints = false
scoreLabel.textAlignment = .right
scoreLabel.font = UIFont.systemFont(ofSize: 24)
scoreLabel.text = "Score: 0"
view.addSubview(scoreLabel)
answerLabel = UILabel()
answerLabel.translatesAutoresizingMaskIntoConstraints = false
answerLabel.font = UIFont.systemFont(ofSize: 24)
answerLabel.text = "ANSWER"
answerLabel.numberOfLines = 1
answerLabel.textAlignment = .center
answerLabel.setContentHuggingPriority(UILayoutPriority(1), for: .vertical)
view.addSubview(answerLabel)
let buttonsView = UIView()
buttonsView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(buttonsView)
let row1View = UIView()
row1View.translatesAutoresizingMaskIntoConstraints = false
buttonsView.addSubview(row1View)
let row2View = UIView()
row2View.translatesAutoresizingMaskIntoConstraints = false
row2View.setContentHuggingPriority(.defaultLow, for: .vertical)
buttonsView.addSubview(row2View)
let row3View = UIView()
row3View.translatesAutoresizingMaskIntoConstraints = false
buttonsView.addSubview(row3View)
NSLayoutConstraint.activate([
scoreLabel.topAnchor.constraint(equalTo: view.layoutMarginsGuide.topAnchor),
scoreLabel.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor, constant: 0),
answerLabel.topAnchor.constraint(equalTo: scoreLabel.bottomAnchor, constant: 25),
answerLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor),
buttonsView.widthAnchor.constraint(equalToConstant: 1000),
buttonsView.heightAnchor.constraint(equalToConstant: 300),
buttonsView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
buttonsView.topAnchor.constraint(equalTo: answerLabel.bottomAnchor, constant: 20),
buttonsView.bottomAnchor.constraint(equalTo: view.layoutMarginsGuide.bottomAnchor, constant: -20),
row1View.leftAnchor.constraint(equalTo: buttonsView.leftAnchor),
row1View.topAnchor.constraint(equalTo: buttonsView.topAnchor),
row1View.widthAnchor.constraint(equalTo: buttonsView.widthAnchor),
//row1View.heightAnchor.constraint(equalTo: buttonsView.heightAnchor, multiplier: 0.333, constant: 0),
//row1View.heightAnchor.constraint(equalToConstant: 100),
row2View.leftAnchor.constraint(equalTo: buttonsView.leftAnchor),
row2View.topAnchor.constraint(equalTo: row1View.bottomAnchor),
row2View.widthAnchor.constraint(equalTo: buttonsView.widthAnchor),
//row2View.heightAnchor.constraint(equalTo: buttonsView.heightAnchor, multiplier: 0.333, constant: 0),
//row2View.heightAnchor.constraint(equalToConstant: 100),
row3View.leftAnchor.constraint(equalTo: buttonsView.leftAnchor),
row3View.topAnchor.constraint(equalTo: row2View.bottomAnchor),
row3View.widthAnchor.constraint(equalTo: buttonsView.widthAnchor),
//row3View.heightAnchor.constraint(equalTo: buttonsView.heightAnchor, multiplier: 0.333, constant: 0),
//row3View.heightAnchor.constraint(equalToConstant: 100),
])
let width = 100
let height = 100
var i = 10
for row in 0..<3 {
print(row)
switch row {
case 0:
i = 10
case 1:
i = 9
case 2:
i = 7
default:
return
}
for col in 0..<i {
let characterButton = UIButton(type: .system)
characterButton.titleLabel?.font = UIFont.systemFont(ofSize: 36)
characterButton.layer.borderWidth = 1
characterButton.layer.borderColor = UIColor.lightGray.cgColor
characterButton.layer.backgroundColor = UIColor.white.cgColor
characterButton.setTitle("#", for: .normal)
let frame = CGRect(x: col * width, y: row * height, width: width, height: height)
characterButton.frame = frame
switch row {
case 0:
print(row)
print("row 1")
row1View.addSubview(characterButton)
case 1:
print(row)
print("row 2")
row2View.addSubview(characterButton)
case 2:
print(row)
print("row 3")
row3View.addSubview(characterButton)
default:
print("defualt")
return
}
characterButtons.append(characterButton)
characterButton.addTarget(self, action: #selector(characterTapped), for: .touchUpInside)
}
}
buttonsView.backgroundColor = .purple
row1View.backgroundColor = .red
row2View.backgroundColor = .yellow
row3View.backgroundColor = .green
}
在计算每行中放置的按钮的框架的地方有一个错误。
// your code
let frame = CGRect(x: col * width, y: row * height, width: width, height: height)
您不需要更改按钮的 y
位置。它可以只是 0,因为每一行都在它自己的视图中。
// corrected code
let frame = CGRect(x: col * width, y: 0, width: width, height: height)
您还应该为每一行设置高度限制。添加的所有按钮都超出了父视图的范围。这在设置 rowView.clipsToBounds = true
时变得可见。这就是您的按钮不起作用的原因。
我认为循环中也存在问题运行,但我还没有检查过。
您的问题的解决方案:我尝试修复您的示例代码并且它有效。检查 here
有空的时候也可以尝试使用集合视图或堆栈视图来解决问题。
使用 UIStackView
s 有很多好处...主要是它们可用于自动排列和调整子视图的大小,使您的布局很容易适应不同的设备和屏幕尺寸.
这是您的代码示例,已修改为使用堆栈视图来保存按钮(我还添加了一个自定义 CharacterButton
class,它将自动设置用户界面中按钮标签的字体大小-定义范围/比例):
class CharacterButton: UIButton {
// this will automatically set the font size for the button
// if the button width >= 100, font size will be maxSize
// if it's less than 100, font size will be proportional
// with a minimum font size of 20
// these are declared as "var" so they can be changed at run-time if desired
var maxSize: CGFloat = 36
var minSize: CGFloat = 20
var forWidth: CGFloat = 100
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
func commonInit() -> Void {
// set title colors
setTitleColor(.blue, for: .normal)
setTitleColor(.lightGray, for: .highlighted)
// maybe change title color when disabled?
//setTitleColor(.darkGray, for: .disabled)
// give it a border
layer.borderWidth = 1
layer.borderColor = UIColor.lightGray.cgColor
layer.backgroundColor = UIColor.white.cgColor
}
override func layoutSubviews() {
super.layoutSubviews()
let fSize = min(max(minSize, bounds.size.width / forWidth * maxSize), maxSize)
titleLabel?.font = UIFont.systemFont(ofSize: fSize)
}
}
class HangManViewController: UIViewController {
// letterGuess
// usedLetters
// score/lives
var scoreLabel: UILabel!
var answerLabel: UILabel!
var characterButtons = [UIButton]()
var score = 0 {
didSet {
scoreLabel.text = "Score: \(score)"
}
}
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
// create and add the Score label
scoreLabel = UILabel()
scoreLabel.translatesAutoresizingMaskIntoConstraints = false
scoreLabel.textAlignment = .right
scoreLabel.font = UIFont.systemFont(ofSize: 24)
scoreLabel.text = "Score: 0"
view.addSubview(scoreLabel)
// create and add the Answer label
answerLabel = UILabel()
answerLabel.translatesAutoresizingMaskIntoConstraints = false
answerLabel.font = UIFont.systemFont(ofSize: 24)
answerLabel.text = "ANSWER"
answerLabel.numberOfLines = 1
answerLabel.textAlignment = .center
answerLabel.setContentHuggingPriority(UILayoutPriority(1), for: .vertical)
view.addSubview(answerLabel)
// create a view to hold the buttons
let buttonsView = UIView()
buttonsView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(buttonsView)
// create a vertical "outer" stack view
let outerStack = UIStackView()
outerStack.axis = .vertical
outerStack.distribution = .fillEqually
// add it to the buttons holder view
outerStack.translatesAutoresizingMaskIntoConstraints = false
buttonsView.addSubview(outerStack)
// create three "row" stack views
let row1Stack = UIStackView()
row1Stack.axis = .horizontal
row1Stack.distribution = .fillEqually
let row2Stack = UIStackView()
row2Stack.axis = .horizontal
row2Stack.distribution = .fillEqually
let row3Stack = UIStackView()
row3Stack.axis = .horizontal
row3Stack.distribution = .fillEqually
// add the 3 "row" stack views to the "outer" stack view
[row1Stack, row2Stack, row3Stack].forEach {
outerStack.addArrangedSubview([=10=])
}
let g = view.layoutMarginsGuide
NSLayoutConstraint.activate([
// constrain Score label to top-right
scoreLabel.topAnchor.constraint(equalTo: g.topAnchor),
scoreLabel.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: 0),
// constrain Answer label centered horizontally
answerLabel.centerXAnchor.constraint(equalTo: g.centerXAnchor),
// and 4-pts above the grid of buttons
answerLabel.bottomAnchor.constraint(equalTo: buttonsView.topAnchor, constant: -4),
// constrain buttons holder view Leading / Trailing
buttonsView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 0.0),
buttonsView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: 0.0),
// constrain buttons holder view Bottom with 20-pts "padding"
buttonsView.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: -20),
// constrain all 4 sides of "outer" stack view to buttons holder view
outerStack.topAnchor.constraint(equalTo: buttonsView.topAnchor),
outerStack.leadingAnchor.constraint(equalTo: buttonsView.leadingAnchor),
outerStack.trailingAnchor.constraint(equalTo: buttonsView.trailingAnchor),
outerStack.bottomAnchor.constraint(equalTo: buttonsView.bottomAnchor),
])
let letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".map { String([=10=]) }
var j = 0
// loop through the 3 "rows" adding 10, 9 and 7 buttons
for (thisRow, numButtonsInThisRow) in zip([row1Stack, row2Stack, row3Stack], [10, 9, 7]) {
for i in 0..<10 {
if i < numButtonsInThisRow {
// create a button
let characterButton = CharacterButton()
// set its title
characterButton.setTitle(letters[j], for: .normal)
// maybe set button title to "#" when disabled?
//characterButton.setTitle("#", for: .disabled)
// give button a touchUp target
characterButton.addTarget(self, action: #selector(self.characterTapped(_:)), for: .touchUpInside)
// add button to current row stack view
thisRow.addArrangedSubview(characterButton)
// add button to characterButtons Array
characterButtons.append(characterButton)
// increment j
j += 1
} else {
// we're past the number of character buttons that should be on this row
// so "fill it out" with bordered views
let v = UIView()
v.layer.borderWidth = 1
v.layer.borderColor = UIColor.lightGray.cgColor
v.layer.backgroundColor = UIColor.white.cgColor
thisRow.addArrangedSubview(v)
}
}
}
// we want square buttons, so
// we only need to set the first button to have a 1:1 height:width ratio
// the stack views' fillEqually distribution will handle the rest
if let v = characterButtons.first {
v.heightAnchor.constraint(equalTo: v.widthAnchor).isActive = true
}
// just so we can see the frame of the answer label
answerLabel.backgroundColor = .green
}
@objc func characterTapped(_ sender: UIButton) {
// character button tapped
// get its title
let s = sender.currentTitle ?? "no title"
// do we want to disable it?
//sender.isEnabled = false
// for now, print the Letter to the debug console
print("Button \(s) was tapped!")
}
}
结果:
我正在构建一个简单的刽子手游戏。 我用 UIButtons 构建了一个简单的键盘。键盘在子视图内,每一行都是一个单独的子视图。
按钮不可点击,我可以让顶行工作,但其他行被推开。
我已经尝试设置 NSLayoutConstraint 高度锚点,它会将 UIButton 推出相应的视图。
class ViewController: UIViewController {
// letterGuess
// usedLetters
// score/lives
var scoreLabel: UILabel!
var answerLabel: UILabel!
var characterButtons = [UIButton]()
var score = 0 {
didSet {
scoreLabel.text = "Score: \(score)"
}
}
override func loadView() {
view = UIView()
view.backgroundColor = .white
scoreLabel = UILabel()
scoreLabel.translatesAutoresizingMaskIntoConstraints = false
scoreLabel.textAlignment = .right
scoreLabel.font = UIFont.systemFont(ofSize: 24)
scoreLabel.text = "Score: 0"
view.addSubview(scoreLabel)
answerLabel = UILabel()
answerLabel.translatesAutoresizingMaskIntoConstraints = false
answerLabel.font = UIFont.systemFont(ofSize: 24)
answerLabel.text = "ANSWER"
answerLabel.numberOfLines = 1
answerLabel.textAlignment = .center
answerLabel.setContentHuggingPriority(UILayoutPriority(1), for: .vertical)
view.addSubview(answerLabel)
let buttonsView = UIView()
buttonsView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(buttonsView)
let row1View = UIView()
row1View.translatesAutoresizingMaskIntoConstraints = false
buttonsView.addSubview(row1View)
let row2View = UIView()
row2View.translatesAutoresizingMaskIntoConstraints = false
row2View.setContentHuggingPriority(.defaultLow, for: .vertical)
buttonsView.addSubview(row2View)
let row3View = UIView()
row3View.translatesAutoresizingMaskIntoConstraints = false
buttonsView.addSubview(row3View)
NSLayoutConstraint.activate([
scoreLabel.topAnchor.constraint(equalTo: view.layoutMarginsGuide.topAnchor),
scoreLabel.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor, constant: 0),
answerLabel.topAnchor.constraint(equalTo: scoreLabel.bottomAnchor, constant: 25),
answerLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor),
buttonsView.widthAnchor.constraint(equalToConstant: 1000),
buttonsView.heightAnchor.constraint(equalToConstant: 300),
buttonsView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
buttonsView.topAnchor.constraint(equalTo: answerLabel.bottomAnchor, constant: 20),
buttonsView.bottomAnchor.constraint(equalTo: view.layoutMarginsGuide.bottomAnchor, constant: -20),
row1View.leftAnchor.constraint(equalTo: buttonsView.leftAnchor),
row1View.topAnchor.constraint(equalTo: buttonsView.topAnchor),
row1View.widthAnchor.constraint(equalTo: buttonsView.widthAnchor),
//row1View.heightAnchor.constraint(equalTo: buttonsView.heightAnchor, multiplier: 0.333, constant: 0),
//row1View.heightAnchor.constraint(equalToConstant: 100),
row2View.leftAnchor.constraint(equalTo: buttonsView.leftAnchor),
row2View.topAnchor.constraint(equalTo: row1View.bottomAnchor),
row2View.widthAnchor.constraint(equalTo: buttonsView.widthAnchor),
//row2View.heightAnchor.constraint(equalTo: buttonsView.heightAnchor, multiplier: 0.333, constant: 0),
//row2View.heightAnchor.constraint(equalToConstant: 100),
row3View.leftAnchor.constraint(equalTo: buttonsView.leftAnchor),
row3View.topAnchor.constraint(equalTo: row2View.bottomAnchor),
row3View.widthAnchor.constraint(equalTo: buttonsView.widthAnchor),
//row3View.heightAnchor.constraint(equalTo: buttonsView.heightAnchor, multiplier: 0.333, constant: 0),
//row3View.heightAnchor.constraint(equalToConstant: 100),
])
let width = 100
let height = 100
var i = 10
for row in 0..<3 {
print(row)
switch row {
case 0:
i = 10
case 1:
i = 9
case 2:
i = 7
default:
return
}
for col in 0..<i {
let characterButton = UIButton(type: .system)
characterButton.titleLabel?.font = UIFont.systemFont(ofSize: 36)
characterButton.layer.borderWidth = 1
characterButton.layer.borderColor = UIColor.lightGray.cgColor
characterButton.layer.backgroundColor = UIColor.white.cgColor
characterButton.setTitle("#", for: .normal)
let frame = CGRect(x: col * width, y: row * height, width: width, height: height)
characterButton.frame = frame
switch row {
case 0:
print(row)
print("row 1")
row1View.addSubview(characterButton)
case 1:
print(row)
print("row 2")
row2View.addSubview(characterButton)
case 2:
print(row)
print("row 3")
row3View.addSubview(characterButton)
default:
print("defualt")
return
}
characterButtons.append(characterButton)
characterButton.addTarget(self, action: #selector(characterTapped), for: .touchUpInside)
}
}
buttonsView.backgroundColor = .purple
row1View.backgroundColor = .red
row2View.backgroundColor = .yellow
row3View.backgroundColor = .green
}
在计算每行中放置的按钮的框架的地方有一个错误。
// your code
let frame = CGRect(x: col * width, y: row * height, width: width, height: height)
您不需要更改按钮的 y
位置。它可以只是 0,因为每一行都在它自己的视图中。
// corrected code
let frame = CGRect(x: col * width, y: 0, width: width, height: height)
您还应该为每一行设置高度限制。添加的所有按钮都超出了父视图的范围。这在设置 rowView.clipsToBounds = true
时变得可见。这就是您的按钮不起作用的原因。
我认为循环中也存在问题运行,但我还没有检查过。
您的问题的解决方案:我尝试修复您的示例代码并且它有效。检查 here
有空的时候也可以尝试使用集合视图或堆栈视图来解决问题。
使用 UIStackView
s 有很多好处...主要是它们可用于自动排列和调整子视图的大小,使您的布局很容易适应不同的设备和屏幕尺寸.
这是您的代码示例,已修改为使用堆栈视图来保存按钮(我还添加了一个自定义 CharacterButton
class,它将自动设置用户界面中按钮标签的字体大小-定义范围/比例):
class CharacterButton: UIButton {
// this will automatically set the font size for the button
// if the button width >= 100, font size will be maxSize
// if it's less than 100, font size will be proportional
// with a minimum font size of 20
// these are declared as "var" so they can be changed at run-time if desired
var maxSize: CGFloat = 36
var minSize: CGFloat = 20
var forWidth: CGFloat = 100
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
func commonInit() -> Void {
// set title colors
setTitleColor(.blue, for: .normal)
setTitleColor(.lightGray, for: .highlighted)
// maybe change title color when disabled?
//setTitleColor(.darkGray, for: .disabled)
// give it a border
layer.borderWidth = 1
layer.borderColor = UIColor.lightGray.cgColor
layer.backgroundColor = UIColor.white.cgColor
}
override func layoutSubviews() {
super.layoutSubviews()
let fSize = min(max(minSize, bounds.size.width / forWidth * maxSize), maxSize)
titleLabel?.font = UIFont.systemFont(ofSize: fSize)
}
}
class HangManViewController: UIViewController {
// letterGuess
// usedLetters
// score/lives
var scoreLabel: UILabel!
var answerLabel: UILabel!
var characterButtons = [UIButton]()
var score = 0 {
didSet {
scoreLabel.text = "Score: \(score)"
}
}
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
// create and add the Score label
scoreLabel = UILabel()
scoreLabel.translatesAutoresizingMaskIntoConstraints = false
scoreLabel.textAlignment = .right
scoreLabel.font = UIFont.systemFont(ofSize: 24)
scoreLabel.text = "Score: 0"
view.addSubview(scoreLabel)
// create and add the Answer label
answerLabel = UILabel()
answerLabel.translatesAutoresizingMaskIntoConstraints = false
answerLabel.font = UIFont.systemFont(ofSize: 24)
answerLabel.text = "ANSWER"
answerLabel.numberOfLines = 1
answerLabel.textAlignment = .center
answerLabel.setContentHuggingPriority(UILayoutPriority(1), for: .vertical)
view.addSubview(answerLabel)
// create a view to hold the buttons
let buttonsView = UIView()
buttonsView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(buttonsView)
// create a vertical "outer" stack view
let outerStack = UIStackView()
outerStack.axis = .vertical
outerStack.distribution = .fillEqually
// add it to the buttons holder view
outerStack.translatesAutoresizingMaskIntoConstraints = false
buttonsView.addSubview(outerStack)
// create three "row" stack views
let row1Stack = UIStackView()
row1Stack.axis = .horizontal
row1Stack.distribution = .fillEqually
let row2Stack = UIStackView()
row2Stack.axis = .horizontal
row2Stack.distribution = .fillEqually
let row3Stack = UIStackView()
row3Stack.axis = .horizontal
row3Stack.distribution = .fillEqually
// add the 3 "row" stack views to the "outer" stack view
[row1Stack, row2Stack, row3Stack].forEach {
outerStack.addArrangedSubview([=10=])
}
let g = view.layoutMarginsGuide
NSLayoutConstraint.activate([
// constrain Score label to top-right
scoreLabel.topAnchor.constraint(equalTo: g.topAnchor),
scoreLabel.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: 0),
// constrain Answer label centered horizontally
answerLabel.centerXAnchor.constraint(equalTo: g.centerXAnchor),
// and 4-pts above the grid of buttons
answerLabel.bottomAnchor.constraint(equalTo: buttonsView.topAnchor, constant: -4),
// constrain buttons holder view Leading / Trailing
buttonsView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 0.0),
buttonsView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: 0.0),
// constrain buttons holder view Bottom with 20-pts "padding"
buttonsView.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: -20),
// constrain all 4 sides of "outer" stack view to buttons holder view
outerStack.topAnchor.constraint(equalTo: buttonsView.topAnchor),
outerStack.leadingAnchor.constraint(equalTo: buttonsView.leadingAnchor),
outerStack.trailingAnchor.constraint(equalTo: buttonsView.trailingAnchor),
outerStack.bottomAnchor.constraint(equalTo: buttonsView.bottomAnchor),
])
let letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".map { String([=10=]) }
var j = 0
// loop through the 3 "rows" adding 10, 9 and 7 buttons
for (thisRow, numButtonsInThisRow) in zip([row1Stack, row2Stack, row3Stack], [10, 9, 7]) {
for i in 0..<10 {
if i < numButtonsInThisRow {
// create a button
let characterButton = CharacterButton()
// set its title
characterButton.setTitle(letters[j], for: .normal)
// maybe set button title to "#" when disabled?
//characterButton.setTitle("#", for: .disabled)
// give button a touchUp target
characterButton.addTarget(self, action: #selector(self.characterTapped(_:)), for: .touchUpInside)
// add button to current row stack view
thisRow.addArrangedSubview(characterButton)
// add button to characterButtons Array
characterButtons.append(characterButton)
// increment j
j += 1
} else {
// we're past the number of character buttons that should be on this row
// so "fill it out" with bordered views
let v = UIView()
v.layer.borderWidth = 1
v.layer.borderColor = UIColor.lightGray.cgColor
v.layer.backgroundColor = UIColor.white.cgColor
thisRow.addArrangedSubview(v)
}
}
}
// we want square buttons, so
// we only need to set the first button to have a 1:1 height:width ratio
// the stack views' fillEqually distribution will handle the rest
if let v = characterButtons.first {
v.heightAnchor.constraint(equalTo: v.widthAnchor).isActive = true
}
// just so we can see the frame of the answer label
answerLabel.backgroundColor = .green
}
@objc func characterTapped(_ sender: UIButton) {
// character button tapped
// get its title
let s = sender.currentTitle ?? "no title"
// do we want to disable it?
//sender.isEnabled = false
// for now, print the Letter to the debug console
print("Button \(s) was tapped!")
}
}
结果: