Update widthAnchor on Device orientation - ios

I have this constraint in my controller for a view like this:
someView.widthAnchor.constraint(equalToConstant: view.bounds.width).isActive = true
Now I've added this constraint in willLayoutSubviews to update it on device rotation.
But it doesn't seem to update, even more like it adds another width constraint, which of course conflicts with the old width constraint.
Now I don't really know a proper solution to update this width constraint, but it seems to me like I need to remove the constraint first and then set it again.
Which if I test this like this:
someView.constraints.forEach {
someView.removeContraint($0)
}
This works like expected, only it deletes of course some constraints I don't want to delete... so also not a solution.

Sol1
hook the width constraint as IBOutlet and change it's constant in code like this
self.widthCon.constant = //value
self.view.layoutIfNeeded()
Sol2
delete the constraint with identifier
someView.constraints.forEach {
if $0.identifier == "set_id" {
someView.removeConstraint($0)
someView.widthAnchor.constraint(equalToConstant: view.bounds.width).isActive = true
}
}

Alternate Solution:
If you have a reference to the superview of someView then you can simply assign equal width constraints like so:
someView.widthAnchor.constraint(equalTo: superView.widthAnchor)
This way you can let the Autolayout engine update the width automatically when the device orientation changes.

Related

Need to change size of a textField when keyboardWillShow notification is received

I want the text field to do the next when the keyboard appears on the screen:
Move above the clave
Stretch to the width of the screen
The first item works, but the second one - doesn't.
When opening the application, the text field is attached with snap kit constructs
My code:
#objc private func keyboardWillShow (notification: NSNotification) {
guard let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue else { return }
UIView.animate(withDuration: 0.2) {
self.textField.widthAnchor.constraint(equalToConstant: self.view.frame.width).isActive = true
self.textField.frame.origin.y = keyboardSize.origin.y - self.textField.frame.height
}
}
You cannot change the weight of the text field with rounded corners.
Consider to use the UITextView or change text field border style to:
textField.borderStyle = UITextBorderStyleRoundedRect;
UPD:
I'm really sorry, I made mistake and read the question incorrectly.
In this case, you need to check the logs for autolayout errors. This issue can appear because you have conflicting constraints:
You have added the width constraint using a storyboard or xib it may conflict with the constraint you are setting in the keyboardWillShow method.
You have added trailing constraint and getting the next conflict. Thus, the trailing constraint trying to make the width smaller than you set to the width constraint:
Solutions:
If you are using storyboard constraints create an outlet of the constraint from the storyboard and change it in the next way:
self.widthConstraint.constant = self.view.frame.width;
Make trailing constraint less than or equal rather than equal. In this way, the width will be changed but the trailing constraint will prevent the text fields to be bigger than the desired paddings. Another way will be to update the trailing constraint instead of the width constraint, but you will need more calculations.

How do I resize my UITableView using Autolayout?

I have a UITableView in a ViewController in a Storyboard (not a UITableViewController). What I want to do is add a custom UIView above the TableView in code. When the View is not there, the TableView's top anchor is anchored to PrimaryNavCollectionViewOutlet. I store this constraint as an outlet, and then if I have to add the View, I can use this outlet to remove the storyboard constraint.
I then constrain the inserted View to be below where the TableView was, and constraint the TableView to be below that.
Here's my code:
if (_viewAboveTableView != null)
{
TableView.RemoveConstraint(TableViewTopConstraint);
View.AddSubview(_viewAboveTableView);
_viewAboveTableView.TranslatesAutoresizingMaskIntoConstraints = false;
TableView.TranslatesAutoresizingMaskIntoConstraints = false;
_viewAboveTableView.LeadingAnchor.ConstraintEqualTo(View.LeadingAnchor).Active = true;
_viewAboveTableView.TopAnchor.ConstraintEqualTo(PrimaryNavCollectionViewOutlet.BottomAnchor).Active = true;
_viewAboveTableView.TrailingAnchor.ConstraintEqualTo(View.TrailingAnchor).Active = true;
_viewAboveTableView.BottomAnchor.ConstraintEqualTo(TableView.TopAnchor).Active = true;
}
Unfortunately, when I run it, I can't see _viewAboveTableView. I feel like I'm missing something easy, but I can't figure out what. I've tried LayoutIfNeeded() and a few other methods on the View, but they don't make it appear. What have I missed?
Add height constraint to _viewAboveTableView.
Or
Make sure _viewAboveTableView has content that will specify intrinsic content size -- it should have properly laid-out subviews with content size (intrinsic or explicit via layouts. e.g. image, label etc.)
My guess is _viewAboveTableView is not getting inflated because it doesn't specify intrinsic content size (height > 0). If it's wrong constraints, you should be able to see it in the console.
It looks like the problem with what I was doing was that TableView.RemoveConstraint(TableViewTopConstraint); didn't have the intended effect.
From this answer I learned that RemoveConstraint is, or is about to be, deprecated in favour of TableViewTopConstraint.Active = false;. This made my code work the way that was intended.

How do I update a constraint from the Storyboard without an IBOutlet or Identifier?

I have a lot of views that are created in the storyboard, but I want them to be able to update their constraints dynamically without having to use an IBOutlet each time.
I started by making a custom class for the superview of the view I want to update, and change its subview's bottom constraint like this:
myView.constraints.filter{ $0.firstAnchor is NSLayoutAttribute.bottom }.constant -= 200
'NSLayoutAttribute.bottom' doesn't seem to be the correct way to check the type of the Anchor.
How do I check the type of the constraints I want to change?
Am I correct in updating the constraints in the superview of the view I want to change, not the view itself?
NSLayoutConstraint from iOS7 have a property called identifier, from code or from IB you can set this property.
After that to get the constraint you are looking for is just a matter of searching it in a particular view.
Consider this UIView extension:
func constraint(withIdentifier:String) -> NSLayoutConstraint? {
return constraints.filter{ $0.identifier == withIdentifier }.first
}
As per dahlia_boy's suggestion, I used UIView.animate to achieve this functionality, however it doesn't seem to be permanent:
translatesAutoresizingMaskIntoConstraints = true
UIView.animate(withDuration: 1, animations: {
self.frame.size.height -= 200
})

How to access Constraint Data Programatically?

I would like to access firstAttribute constraint property programatically. so that i can able to find if a constraint is height constraint,width constraint,topMargin constraint etc...
when i try,
print(constraint.firstAttribute)
i get the general result as
"NSLayoutAttribute"
but what i want more specific result to treat the constraints differently based on it attribute(height,width,topMargin etc..) type.
The property on the constraint that you're looking for is firstAttribute (or secondAttribute). However, there's really no reason you should need to "guess" which constraint you're looking at - just store the constraints as properties and name them accordingly.
EDIT: to tell which type of attribute you have, switch over it:
switch myConstraint.firstAttribute {
case .height:
// height constraint
case .leading:
// leading constraint
case .topMargin:
// top margin constraint
// etc
}
The solution for this is to store the constraint as a property. You can do this with an outlet from a storyboard or nib (just like a button or label) or in code.
That way, you don’t have to dive into the view to try and find the constraint. You just access it like...
buttonHeightConstraint.constant = 50
Etc...
For me firstAttribute didn't work at all, and also, it's not compatible with versions prior to iOS 9.0
So I finally solved by assigning an identifier to the NSLayoutConstraint object. Then, you can iterate though the constraints of your view and compare the identifier to retrieve the desired constraint.
yourConstraint.identifier = "yourString"
So:
for tmpConst in self.view.constraints {
if tmpConst.identifier == "yourString" {
return tmpConst
}
}
Will return your constraint.

Swift: Views not adjusting to programmatic constraints

I have a view that I am making hidden at the bottom of the screen, and want the scrollView above it to adjust and fill the void space.
The view at the bottom of the screen is a GADBannerView and has a fixed height of 50 (bannerHeight). The scroll view above it has a constraint to the bottom of the container that equals 50 (scrollConstraint). See photo.
In viewDidLoad is am setting these constraints to the following:
bannerHeight.constant = 0
scrollConstraint.constant = 0
This is causing the bannerView did disappear but the scroll view is staying in it's original position and not filling the void space.
You can force the superview to take into account the change of the constraint because this does not happen automatically. Add your code to viewDidLayoutSubviews() instead or simply call view.layoutIfNeeded() after you set the constants to 0 in the viewDidLoad().
If this does not work, you can try this alternative approach:
Go to your Storyboard and click on the scroll view's bottom constraint (the blue line that gives the scroll view its bottom constraint of 50). In the Attributes Inspector you should be able to see details about your constraint, it should look something like this
In the field that asks for an Identifier, give it the name "ScrollViewBottom" or whatever name you like.
Now loop over all the constraints that make up your scroll view and use the identifier name to find the correct one and change it's constant as follows
for constraint in yourScrollView.superview!.constraints {
if constraint.identifier == "ScrollViewBottom" {
constraint.constant = 0
}
}
Finally, force the view to take into account of this change by calling the following straight after
view.layoutIfNeeded()

Resources