'Unresponsive UIButton in subview added to UIStackView

In the detailViewController of a UISplitView I have subviews added to a UIStackView inside a UIScrollView.

Just using system buttons without subviews or images, results in responsive buttons, but subviews seem to interfere.

Enabling touch is specifically coded. I have attempted to keep each view inside the containing view so there will be no overlap to invalidate receiving touch events, but not sure if this is done properly. Each subview contains a label and a custom button with an image. The subview is then added to the stackview, and the stackview to the scrollview.

Thanks for any help.

override func viewDidLoad() {
    super.viewDidLoad()

    scrollView = UIScrollView()
    scrollView.translatesAutoresizingMaskIntoConstraints = false
    view.addSubview(scrollView)

    // Constrain the scroll view within the detailView
    view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[scrollView]|", options: .AlignAllCenterX, metrics: nil, views: ["scrollView": scrollView]))
    view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[scrollView]|", options: .AlignAllCenterX, metrics: nil, views: ["scrollView": scrollView]))


    stackView = UIStackView()

    stackView.frame = CGRectMake(0,0,view.frame.width, 1000)
    stackView.translatesAutoresizingMaskIntoConstraints = false
    stackView.axis = .Vertical
    scrollView.contentSize = CGSizeMake(400, 1000)
    scrollView.addSubview(stackView)

    // Constrain the stackView within the scrollView
scrollView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[stackView]|", options: NSLayoutFormatOptions.AlignAllCenterX, metrics: nil, views: ["stackView": stackView]))
scrollView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[stackView]", options: NSLayoutFormatOptions.AlignAllCenterX, metrics: nil, views: ["stackView": stackView]))


    let selectedGroup: Group = GroupArray[5]

    let descriptorsArray = selectedGroup.descriptorsArray

    for descriptor in descriptorsArray {
        // Create a subview for each descriptor

        let subView = UIView()
        subView.frame = CGRectMake(0 , 0, self.stackView.frame.width-10, 54)
        subView.backgroundColor = UIColor.yellowColor()

        subView.heightAnchor.constraintEqualToConstant(54.0).active = true
        // Create a label for Descriptor subview

        let label = UILabel(frame: CGRectMake(20, 0, 200, 50))
        label.text = descriptor.name
        label.font = UIFont.boldSystemFontOfSize(22.0)
        label.textAlignment = .Left
        label.textColor = UIColor.brownColor()
        label.backgroundColor = UIColor.greenColor()
        label.heightAnchor.constraintEqualToConstant(50.0).active = true
        subView.addSubview(label)

        // Create a button for Checkbox
        let btn = UIButton()
        btn.frame = CGRectMake(220, 0, 50, 50)
        btn.backgroundColor = UIColor.blueColor()
        btn.setImage(UIImage(named:"checked.png"), forState: UIControlState.Normal)

        btn.heightAnchor.constraintLessThanOrEqualToConstant(50.0)
        btn.widthAnchor.constraintLessThanOrEqualToConstant(50.0)

        btn.addTarget(self, action: "btnPressed:", forControlEvents: UIControlEvents.TouchUpInside)

        subView.addSubview(btn)
        btn.userInteractionEnabled = true
        subView.userInteractionEnabled = true
        stackView.userInteractionEnabled = true
        scrollView.userInteractionEnabled = true
        stackView.addArrangedSubview(subView)


    }
}

func btnPressed(sender: UIButton!) {

    print("btn Pressed")

}


Solution 1:[1]

I have had the exact same issue: a StackView which contains views. Each view contains a button and a label. The views are only containers for layout reasons.

In my case: I did not give the view a height constraint and it seems that it had a zero height (after changing the background color for debugging I did not see the view), but the button and label was visible (but unresponsive).

After I have added a height constraint to the layout view the (debug) background color was visible and the buttons responded as expected.

Solution 2:[2]

In my case, it was the aligment property of the StackView that was causing the problem.

When I set that property to Fill instead of Center the problem dissappeared.

Solution 3:[3]

I just ran into this issue myself. In my case, I had a UIStackView as a subview of my UIButton. I needed to set isUserInteractionEnabled = false on the stack view in order to get my button to work. This is probably a wise thing to set on any UIButton subview.

Solution 4:[4]

following theGuy's answer, I used the sherlock app and I immediately found the problem:

enter image description here

Solution 5:[5]

In my case, I had set a custom view subclass in loadView. That subclass had isUserInteractionEnabled = false which translated down to all the sub views including my stackView and all its views and buttons.

Solution 6:[6]

I noticed a bug (I guess) in XCode 12. When my IBOutlet func (on swift) is empty, and I put a breakpoint inside the body of the empty func, or on the func declaration itself, then touch the button - XCode doesn't stop on my breakpoint (tested on Simulator).

Solution 7:[7]

In my case, it was just Xcode's bug. I've just closed and reopened it. It just worked. My current Xcode version is 11.4.1.

Solution 8:[8]

For me the problem was that I was instantiating views for Stack View from storyboard, and my ViewController was not added to a views structure, but UIView did. This why button actions from UIViewController subclass didn't work. So the answer of Mostafa Aghajani from here https://stackoverflow.com/a/42179529/344386 helped me. If I do something like this:

    let testViewController = storyboard.instantiateViewController(withIdentifier: "TestViewController") as! TestViewController
    
    view.addSubview(testViewController.view) 
    // OR FOR STACK VIEW
    stackView.addArrangedSubview(testViewController.view)

Normally views structure when I check "XCode / Debug / View debugging / Capture view hierarchy" looks like UIViewController / UIView. But not in this case. The key was to do like this:

    let testViewController = storyboard.instantiateViewController(withIdentifier: "TestViewController") as! TestViewController
    self.addChild(testViewController) // this is the key

    view.addSubview(testViewController.view) 
    // OR FOR STACK VIEW
    stackView.addArrangedSubview(testViewController.view)

Then UIViewController was added in a views hierarchy and my UIButton inside of testViewController started to work. That's all is a kind of shamanism, may be I'm just doing something wrong.

Solution 9:[9]

I have had come cross the same issue. The reason is that i set button.alpha = 0, while setting the button.layer.opacity = 1.0. In this case, the button will not response to actions although it's visible. So setting button.alpha = 1.0 is the answer. May that help!

Solution 10:[10]

I had this happen in my stackview because the button went out of bounds of the stackview - but this was not obvious in the storyboard view. To confirm this as the issue, select the stackview and turn on "clips to bounds" in the attribute inspector to see if your button is going out of the stackview. You may have to check each stackview in the parent hierarchy all the way to the topmost stackview. Check this on all the phone sizes too - what might work on the iPhone 11 may clip on the iPhone4s.

Solution 11:[11]

Well, it is so obvious that you might not feel checking it necessary. I've spent maybe an hour trying all the other answers, and I want to save your time.

Check the code of your custom cell class, especially awakeFromNib method, to see if userInteractionEnabled of the cell is set to false somewhere. Set it to true. Voila! :]

Solution 12:[12]

Make sure you add your view with addArrangedSubview.

I had this issue because I added the button to the UIStackView with addSubview.