I placed my UI button inside stack view of storyboard in UIKit App. and I enabled user interaction to both stack view and button. My button width and height are 20,20. I am using this UIbutton for checkbox sometimes it is responsive and sometimes I have to click multiple times. I tried increasing the size of the box but no luck.when I use tip of my nail it works and if I use my entire finger it won't work. I guess when my finger touches both stackview and button it won't work
Posting this answer, as per the OP's comments...
The issue is unrelated to the button being in a stack view -- the problem, is the size of the button.
Apple's Human Interface Guidelines states:
As a general rule, a button needs a hit region of at least 44x44 pt
That is not a requirement, but as you've seen it can be very tough to consistently tap a 20x20 button.
Options for a "checkbox button" could include:
hitTest(_:with:)
to expand the touch areaUIButton
and handling the touchesUp to you to decide which approach fits best with your overall design / UI goals.
Edit - in response to comment...
Searching for swift custom checkbox button
returns lots of results.
If you want to look at a very simple example, here is some sample code:
class CheckBoxButton: UIButton {
public var isChecked: Bool = false {
didSet {
if isChecked {
setImage(checkedImg, for: [])
} else {
setImage(unCheckedImg, for: [])
}
}
}
private var unCheckedImg: UIImage!
private var checkedImg: UIImage!
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
private func commonInit() {
guard let cImg = UIImage(systemName: "checkmark.square"),
let uImg = UIImage(systemName: "square")
else {
fatalError("Could not create check box images!!!")
}
self.unCheckedImg = uImg
self.checkedImg = cImg
setImage(unCheckedImg, for: [])
}
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let vStack = UIStackView()
vStack.axis = .vertical
vStack.spacing = 8
for i in 0..<5 {
let hStack = UIStackView()
hStack.alignment = .center
hStack.spacing = 8
let label = UILabel()
label.backgroundColor = UIColor(white: 0.95, alpha: 1.0)
label.text = "Option \(i)"
label.font = .systemFont(ofSize: 28.0, weight: .light)
let btn = CheckBoxButton()
btn.backgroundColor = .white
btn.widthAnchor.constraint(equalToConstant: 44.0).isActive = true
btn.heightAnchor.constraint(equalTo: btn.widthAnchor).isActive = true
btn.addTarget(self, action: #selector(btnTapped(_:)), for: .touchUpInside)
hStack.addArrangedSubview(label)
hStack.addArrangedSubview(btn)
vStack.addArrangedSubview(hStack)
hStack.isUserInteractionEnabled = true
}
vStack.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(vStack)
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
vStack.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
vStack.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
vStack.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
])
// if we want to see the actual button frames...
// comment-out this return() line
return()
for hs in vStack.arrangedSubviews {
if let hs = hs as? UIStackView,
let btn = hs.arrangedSubviews.last as? CheckBoxButton
{
btn.backgroundColor = .yellow
}
}
}
@objc func btnTapped(_ sender: UIButton) {
guard let btn = sender as? CheckBoxButton else { return }
btn.isChecked.toggle()
}
}