How to access Constraint Data Programatically? - ios

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.

Related

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.

Update widthAnchor on Device orientation

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.

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

Which time to add constraint to superView?

I wanna add constraints toAview on Aview.superView without Xib and Storyboard, i add constraint code in the function -(void)didMoveToSuperview, it worked. The second time i add Aview to cell.contentView, when i start to scroll , it crashed;
Here is the error info :
A multiplier of 0 or a nil second item together with a location for the first attribute creates an illegal constraint of a location equal to a constant. Location attributes must be specified in pairs
But i am sure all the params of the multiplier is not 0 or nil .
It seems that the second item(the superView) is nil , so i write the constraint code in a custom function like this :
[cell.contentView addSubview:view];
[view setConstraint];
Then it works;
I just wanna know is there a good way to add constraint in the Aview?In which function ?

Export or Print Auto Layout Constraints from Storyboard iOS

Is it possible to print out the constraints set up in auto layout that you create in a Storyboard? I would like to re-create what I have done in the Storyboard in code.
All instances of UIView has a property named constraints. That is an NSArray of all the NSLayoutConstraint's associated with that particular view. You could traverse a view hierarchy recursively from the root view and then print out the desired layout constraint properties.
// for each view in hierarchy
for (NSLayoutConstraint *constraint in view.constraints) {
// print what you need here
}
Have you tried to open the storyboard file in an external editor (not xCode)?
You can read it, it's just xml.
If you need print the view you should find the constraints in the super view. For example:
view.superview?.constraints.forEach { (constraints: NSLayoutConstraint) in
// If you want to find some specific constrainst
if constraints.firstItem as! NSObject == view && (constraints.firstAttribute == .centerX) {
// Remove it.
constraints.isActive = false
}
}
The accepted answer should only print height and width of the view itself.

Resources