Uibutton Action Is Not Triggered After Constraint Layouts Changed

UIButton action is not triggered after constraint layouts changed

Finally, I have found the solution in another chain, once it became clear that the scrollview's contentview is resizing on scroll event to the original size. (Not clear why this is like this, but that is the fact.)

So I had to add a height constraint to the contentview in the storyboard and create an outlet to it and adjust this constraint when the content size is changing, like this:

@IBOutlet weak var ContentViewHeight: NSLayoutConstraint!

func fillFormWithData() {
dispDescription.text = jSonData[0]["advdescription"]
dispLongDescription.text = jSonData[0]["advlongdesc"]
priceandcurrency.text = jSonData[0]["advprice"]! + " " + jSonData[0]["advpricecur"]!
validitydate.text = jSonData[0]["advdate"]!
let contentRect = CGRect(x: 0, y: 0, width: scrollview.frame.width, height: uzenetbutton.frame.origin.y+uzenetbutton.frame.height+50)

contentview.bounds = contentRect
scrollview.contentSize = contentRect.size

----------- This is the key line to the success ----------
ContentViewHeight.constant = contentRect.size.height

After this is added, it works perfectly.

Contentsize is perfectly as should be

UIButton not responding after set frame within UIScrollview

Check if your UIButton final position is both inside the UITableView and UIScrollView bounds.

It is possible that after you moved it, the UIBUtton is placed outside the bound, and then will not respond to touch events.

One quick set up that can make you verify that is to set the clipToBounds property of your UITableView and UIScrollView to NO, then all content placed outside the bounds will not even be visible.

UIButton stops working when using auto layout

It seems that the problem was the second line:

self.view.translatesAutoresizingMaskIntoConstraints = NO;

With this line the view wasn't full screen, starting at the top left as expected, but started somewhere near the center. Therefore though the buttons appeared to be near the center of the screen they were actually outside of the containing view. When I removed this line everything started to work.

I guess I have discovered a gotcha for translatesAutoresizingMaskIntoConstraints. Though you have to turn it off to use constraints, that is only on the exact views that are using constraints, not for the containing view unless it too is using constraints. In this case I turned off translatesAutoresizingMaskIntoConstraints on the containing view, but should not have as it had no constraints for it.

My UIButton is not triggering the button action when its moved up while the keyboard is shown

Finally i figured out whats causing the issue

i just had to comment out
tap.cancelsTouchesInView = false
this line in viewdid load method...and works perfectly fine..but i dont know why is that .

Why isn't UIButton returning correct constraints?

Here are several comments about your code:

  1. You never added any constraints to any views, so you shouldn't be removing them. iOS (CocoaTouch) added those constraints to those views, so please don't touch them. (In other words: don't call removeConstraint when you didn't call addConstraint). Your control over constraints is activating and deactivating them. Leave the adding and removing to iOS.
  2. When you activate a constraint, a constraint is added (by iOS) to the most common ancestor of the two items mentioned in the constraint. So if the two views are siblings, it will be added to the parent. If the two views are parent and child, the constraint will be added to the parent. If the two views are grandparent and grandchild, it will be added to the grandparent. If the two views are first cousins, the constraint will be added to their common grandparent.
  3. These lines of code:

    let btnHeight = theBtn.heightAnchor.constraint(equalTo: scrollView.heightAnchor)
    if btn == b1{
    b1HeightConstraint = btnHeight

    are creating a new constraint and assigning it to b1HeightConstraint, but you never activated this constraint, so it hasn't have been added to any view at all. So trying to remove it was never going to work, because that constraint exists only in your b1HeightConstraint property. Since it was never activated, it isn't actually constraining anything.

  4. If you want to shrink a button, you need to do one of these: a) modify the constant property of its height constraint OR b) set its height constraint's isActive property to false and then give it a new height constraint OR c) modify the priorities of the active constraints to have Auto Layout choose to use different constraints.

  5. In your view debug hierarchy, all the constraints shown are active constraints (meaning they are available to be used by Auto Layout). The grayed out ones are the ones Auto Layout chose not to use because a higher priority constraint had precedence over it. This causes no conflict. The self.height = 34 (content size) constraint is added by the system to account for content compression and content hugging. UIButtons resist compression with priority 750 and resist expansion with priority 250. The self.height = 34 (content size) constraint is grayed out because content hugging has a priority of 250 and another higher priority constraint was used instead (the constraint which sets the button's height equal to the scrollView's height has priority 1000).

Updated Code:

Here is your modified code. I changed two things:

  1. I made sure b1HeightConstraint was an activated constraint.
  2. I changed the shrink method to deactivate the old height constraint and then create and activate a new one.

Updated code

import UIKit
import Foundation

class ViewController: UIViewController {
var filterView: UIView!
var scrollView: UIScrollView!
var containerView: UIView!

override func loadView() {
filterView = UIView()
view = filterView
view.backgroundColor = #colorLiteral(red: 0.909803926944733, green: 0.47843137383461, blue: 0.643137276172638, alpha: 1.0)

scrollView = UIScrollView()
scrollView.backgroundColor = #colorLiteral(red: 0.474509805440903, green: 0.839215695858002, blue: 0.976470589637756, alpha: 1.0)
scrollView.translatesAutoresizingMaskIntoConstraints = false
scrollView.topAnchor.constraint(equalTo: view.topAnchor, constant: 0).isActive = true
scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
scrollView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
scrollView.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 1).isActive = true
scrollView.isScrollEnabled = true

containerView = UIView()
containerView.backgroundColor = #colorLiteral(red: 0.176470592617989, green: 0.498039215803146, blue: 0.756862759590149, alpha: 1.0)
containerView.translatesAutoresizingMaskIntoConstraints = false

// This is key: connect all four edges of the containerView to
// to the edges of the scrollView
containerView.topAnchor.constraint(equalTo: scrollView.topAnchor).isActive = true
containerView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor).isActive = true
containerView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor).isActive = true
containerView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor).isActive = true

// Making containerView and scrollView the same height means the
// content will not scroll vertically
containerView.widthAnchor.constraint(equalTo: scrollView.widthAnchor).isActive = true

let b1 = Buttons(titleText: "one")
let b2 = Buttons(titleText: "two")
let b3 = Buttons(titleText: "three")
let b4 = Buttons(titleText: "four")
let b5 = Buttons(titleText: "five")
var b1HeightConstraint : NSLayoutConstraint?

override func viewDidLoad() {

let buttonArray = [b1, b2, b3, b4, b5]

b1.button.addTarget(self, action: #selector(ViewController.shrink(_:)), for: .touchUpInside)

var startPoint = containerView.topAnchor

for btn in buttonArray {
let theBtn = btn.button
theBtn.translatesAutoresizingMaskIntoConstraints = false
theBtn.topAnchor.constraint(equalTo: startPoint, constant: 20).isActive = true
theBtn.leadingAnchor.constraint(equalTo: containerView.leadingAnchor).isActive = true
theBtn.trailingAnchor.constraint(equalTo: containerView.trailingAnchor).isActive = true
//theBtn.heightAnchor.constraint(equalTo: scrollView.heightAnchor).isActive = true

startPoint = theBtn.bottomAnchor
let btnHeight = theBtn.heightAnchor.constraint(equalTo: scrollView.heightAnchor)
btnHeight.isActive = true
if btn == b1{
b1HeightConstraint = btnHeight

containerView.bottomAnchor.constraint(equalTo: startPoint, constant: 20).isActive = true


@objc func shrink(_ sender: UIButton) {
b1HeightConstraint?.isActive = false
b1HeightConstraint = sender.heightAnchor.constraint(equalToConstant: 20)
b1HeightConstraint?.isActive = true

class Buttons : NSObject {
let button = UIButton()
init(titleText: String) {
button.backgroundColor = #colorLiteral(red: 0.976470589637756, green: 0.850980401039124, blue: 0.549019634723663, alpha: 1.0)
button.setTitle(titleText, for: .normal)

Options for shrinking the button's height

  1. Setting the constant property of the height constraint

    // shrink button's height by 200 points
    b1HeightConstraint?.constant -= 200
  2. Deactivate the old constraint and create and activate a new one

    // make button height 20 points
    b1HeightConstraint?.isActive = false
    b1HeightConstraint = sender.heightAnchor.constraint(equalToConstant: 20)
    b1HeightConstraint?.isActive = true
  3. Change the priority of the height constraint

    // Set b1HeightConstraint's priority to less than 250, and the
    // *content hugging* with priority 250 will take over and resize
    // the button to its intrinsic height
    b1HeightConstraint?.priority = UILayoutPriority(rawValue: 100)

    Note: For this to work, you have to give the height constraint an initial priority less than 1000 (999 works nicely) because Auto Layout will not let you change the priority of an active constraint if it is required (priority 1000).


    // Just deactivate the buttonHeight constraint and the *content
    // hugging* will take over and it will set the button's height
    // to its intrinsic height
    b1HeightConstraint?.isActive = false

Xcode 8 UIButtons with constraints not showing up

I was missing the point of setting UIButton class to my custom class. I checked my custom class and have seen that I set corner radius on awakeFromNib() method. I called layoutIfNeeded() before I set corner radius which was the solution in my case.

UIButton is not working/Clickable in UIScrollView

I had to provide (-)ve value for bottom space of the ContentView from the superview. It did the job. Initially it was set to zero and because of this there was a large extra space below the bottom and it made the scrolling larger that was not desired.

I have tested it in all the simulators - 4s to 6+ and it is working fine.

Thanks to Nikolay for his continuous help.

Also as I am completely new to iPhone development so I do not know whether my workaround is correct or not. So if there is another solution to the problem then please let me know.

Related Topics

Leave a reply