Unresponsive UIButton in subview added to UIStackV

2019-06-17 03:11发布

问题:

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")

}

回答1:

It seems to be that something is lying over your button and catching all the touch events.

1. Never turn on userInterectionEnabled if you don't need it

There is no reason why a normal view like subView should have set userInteractionEnabled set to true so put it to false.

2. Find the bug:

To find out witch view catches the event start your app on a device and navigate to the stackView. Now in Xcode, press the button "Debug View Hierarchy" (placed right over the console output)

After that you will see every view currently displayed on your device. What you do now is finding out wich views are above your button, and then in code turn their userInteractionEnabled value to false.



回答2:

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.



回答3:

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.



回答4:

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



回答5:

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!



回答6:

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.



回答7:

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.