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"]!
contentview.layoutIfNeeded()
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.
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:
- 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 calladdConstraint
). Your control over constraints is activating and deactivating them. Leave the adding and removing to iOS. - 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.
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 yourb1HeightConstraint
property. Since it was never activated, it isn't actually constraining anything.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'sisActive
property tofalse
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.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.UIButton
s resist compression with priority750
and resist expansion with priority250
. Theself.height = 34 (content size)
constraint is grayed out because content hugging has a priority of250
and another higher priority constraint was used instead (the constraint which sets the button's height equal to the scrollView's height has priority1000
).
Updated Code:
Here is your modified code. I changed two things:
- I made sure
b1HeightConstraint
was an activated constraint. - 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)
view.addSubview(scrollView)
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)
scrollView.addSubview(containerView)
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() {
super.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
containerView.addSubview(theBtn)
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
Setting the
constant
property of the height constraint// shrink button's height by 200 points
b1HeightConstraint?.constant -= 200Deactivate 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 = trueChange 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 (priority1000
).OR
// 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
Programmatically Place Partial Image Over Another in UIview Using Swift 3
Custom Radix Columns (+Special Characters)
How to Get The Coordinates of The Point on a Line That Has The Smallest Distance from Another Point
How to Override Setter in Swift
"'Init' Is Deprecated" Warning After Swift4 Convert
Using an Avplayer Returns a "Non-Multipath Connection" Error
Parametrized Unit Tests in Swift
Error "[Sharesheet] Connection Invalidated" Error iOS13+ But Not on iOS 11.4
How to Create a Circle with Calayer
Access Class Property from Instance
When How to Start Submitting Apps to The iOS App Store Written Using The Swift Programming Language
Modifying Struct Instance Variables Within a Dispatch Closure in Swift
Ambiguous Use of 'Filter' When Converting Project to Swift 4
Check Os Version Using Swift on MAC Os X
Can't Upload .Ipa from Xcode 8, "The Info.Plist Indicates a iOS App, But Submitting a Pkg or Mpkg."
Missing Required Module Firebase - Jenkins Build Error
Loading Image from Assets to Nsimage Keep Getting Error, Expecting Nsimage.Name