Align equal UIViews on the bottom with fixed height - ios

I've been trying to achieve something like the example below for quite a while now without success.
Here's what I have so far:
H:|[firstView][secondView(== firstView)][thirdView(== firstView)][fourthView(== firstView)]|
Which works, but, it yields this result:
I'm trying to get it to look like this:
In other words, I'm trying to place 4 UIViews with equal width and fixed height, on the bottom of the screen.
Does anyone have any input or reference to visual format constraints?

I'm not too sure how to do multiple views in a single constrait but here is how you would do it one view at a time.
This would do your left and right constraints:
NSLayoutConstraint.activate(NSLayoutConstraint.constraints(withVisualFormat: "H:|-0-[V]-0-|", options: [], metrics: nil, views: ["V" : firstview]))
This would constraint the view to the bottom of the screen:
NSLayoutConstraint.activate(NSLayoutConstraint.constraints(withVisualFormat: "V:[V]-0-|", options: [], metrics: nil, views: ["V" : firstview]))
Then to add a height constraint:
NSLayoutConstraint.activate(NSLayoutConstraint.constraints(withVisualFormat: "V:|[V(25)]|", options: [], metrics: nil, views: ["V" : firstview]))

Related

In AutoLayout can you combine both horizontal and vertical constraints using the Visual Format Language?

In our code in a lot of places, I keep seeing this...
containerView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-0-[view]-0-|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: ["view":childView]))
containerView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-0-[view]-0-|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: ["view":childView]))
It just seems redundant to me. I'm wondering if there's a way to combine the formats into a single string; something like this...
containerView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-0-[view]-0-|;V:|-0-[view]-0-|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: ["view":childView]))
So is something like this possible?
For sorry you can't use this , but you can try something like this
let rr = UIView()
rr.backgroundColor = UIColor.red
self.view.addSubview(rr)
rr.translatesAutoresizingMaskIntoConstraints = false
["H:|-100-[rr]-100-|","V:|-100-[rr]-100-|"].forEach{NSLayoutConstraint.activate(NSLayoutConstraint.constraints(withVisualFormat: $0, options: NSLayoutFormatOptions.init(rawValue: 0), metrics: nil, views: ["rr":rr]))}
Comments:
You should be activating constraints instead of adding them to views (since iOS 8).
You can skip the entire options: NSLayoutFormatOptions(rawValue: 0) since that is the default value.
The VFL returns an array of constraints, so you can just add the arrays together.
With those changes we get this line of code:
NSLayoutConstraint.activate(NSLayoutConstraint.constraints(withVisualFormat: "H:|-0-[view]-0-|", metrics: nil, views: ["view":childView]) + NSLayoutConstraint.constraints(withVisualFormat: "V:|-0-[view]-0-|", metrics: nil, views: ["view":childView]))
No, unfortunately the syntax doesn't permit this - see the grammar in the docs
Specifically, the line <orientation> H|V means that the value of orientation
can be H or V but not both.
A good alternative for programmatic autolayout is to use an open source DSL library - two popular examples of which are Cartography and Snapkit
I've used both and found them much less fiddly than VFL, and much less verbose than the underlying Apple API

Cannot convert value of type '[NSLayoutConstraint]' error in swift 2

I want to add constraint to the UIImageView by adding this line of code:
addConstraint(NSLayoutConstraint.constraintsWithVisualFormat("H:|[v0]|", options: NSLayoutFormatOptions(), metrics: nil, views: ["v0": userProfileImageView]))
But xcode show me this error:
How I can fix this error?
Use addConstraints, instead of addConstraint.
constraintsWithVisualFormat returns an array.
Your code becomes:
addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[v0]|", options: [], metrics: nil, views: ["v0": userProfileImageView])
let horizontalprofileViewConstraint = NSLayoutConstraint.constraintsWithVisualFormat("H:|[v0]|", options: NSLayoutFormatOptions(), metrics: nil, views: ["v0": userProfileImageView]
If you click option and hover over horizontalprofileViewConstraint you will see its type as [NSLayoutConstraint] which is already an array.
So what you can do is:
view.addConstraints(horizontalprofileViewConstraint)
if you have more than one view then you cand do:
view.addConstraints(horizontalprofileViewConstraint + verticalprofileViewConstraint)
The + joins to arrays for you.

Swift get error when addConstraints for a UITextField with Visual Format Language

I want to add an UITextField into an UITableCell and set both it's width and height 100%;
My swift code :
nameTextField.translatesAutoresizingMaskIntoConstraints = false
addSubview( nameTextField )
let views = [
"name" : nameTextField
];
let widthLayoutConstraint = NSLayoutConstraint.constraintsWithVisualFormat( "H:|-[name]-|", options: [], metrics: nil, views: views )
nameTextField.addConstraints( widthLayoutConstraint )
let heightLayoutConstraint = NSLayoutConstraint.constraintsWithVisualFormat( "V:|-[name]-|", options: [], metrics: nil, views: views )
nameTextField.addConstraints( heightLayoutConstraint )
I got the follow error message while the table will show:
2016-07-31 19:16:43.027 NOIB[40193:1889520] *** Terminating app due to uncaught exception 'NSGenericException', reason: 'Unable to install constraint on view. Does the constraint reference something from outside the subtree of the view? That's illegal. constraint:<NSLayoutConstraint:0x7ffbfa70f480 UITextField:0x7ffbfa41dff0.leading == NOIB.NameCell:0x7ffbfa41da10'NameCell'.leadingMargin> view:<UITextField: 0x7ffbfa41dff0; frame = (0 0; 0 0); text = ''; clipsToBounds = YES; opaque = NO; layer = <CALayer: 0x7ffbfa41e5c0>>'
It's odd that you are calling addSubview without specifying a view. Usually it is used like:
cell.contentView.addSubview(nameTextField)
Since you aren't specifying a view, then it must be using self.
Two views are involved in the constraints that are returned by your VFL: your nameTextField and its superview. In VFL, "|" represents the superview so it doesn't have to be explicitly included in the view dictionary that you pass in. You need to add the constraints to the view that is higher in the hierarchy. In your case, you need to add the constraints to the superview of nameTextField, which is self. So you could probably do:
self.addConstraints(widthLayoutConstraint)
self.addConstraints(heightLayoutConstraint)
As of iOS 8, there is an easier way. The constraints know which views they need to be added to, so you just have to set their active properties to true. VFL can return multiple constraints, so you need to make all of them active. You can use the class method activateConstraints of NSLayoutConstraint to activate multiple constraints:
let widthLayoutConstraint = NSLayoutConstraint.constraintsWithVisualFormat( "H:|-[name]-|", options: [], metrics: nil, views: views )
NSLayoutConstraint.activateConstraints(widthLayoutConstraint)
let heightLayoutConstraint = NSLayoutConstraint.constraintsWithVisualFormat( "V:|-[name]-|", options: [], metrics: nil, views: views )
NSLayoutConstraint.activateConstraints(heightLayoutConstraint)

Adding Subview creates layout issue

I'm programmatically adding a view inside another view like so:
func addViewControllerToSpecificView( view: UIView, controller: UIViewController) {
controller.willMoveToParentViewController(self)
view.addSubview(controller.view)
self.addChildViewController(controller)
controller.didMoveToParentViewController(self)
}
The issue is that the parent view ends up being wider than it should be (the width of the screen).
When I don't load the subview using the above method, the positioning is perfect (no extra padding). I have no idea why it's adding an extra ~30px
add following line in your code....
controller.view.frame = self.view.layer.bounds;
this will fix the problem.
I dont know that are you adding Auto layout constraint for this view.
Please check that this layout constraints are added in your code, if not then add below constraint after you add childViewController.
let metrices = ["width" : view.bounds.size.width, "height" : view.bounds.size.height]
view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[childView(width)]", options: NSLayoutFormatOptions(rawValue: 0), metrics: metrices, views: ["childView" : controller.view]))
view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:[childView(height)]", options: NSLayoutFormatOptions(rawValue: 0), metrics: metrices, views: ["childView" : controller.view]))

Auto Layout: empty UITextField is only wide enough for 1 character

I'm trying to set up a simple UITableViewCell in which there is a prompt on the left and then a text field right next to it that takes up the rest of the width of the cell; however, with the following constraints, no matter what I set the width of the UITextField to, the width of the field is only wide enough for 1 character. Note: the UITextField is appearing in the correct position (it's directly to the right of the prompt), it's just really small.
cell.contentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-[prompt]-[uitextfield]", options: NSLayoutFormatOptions.AlignAllCenterY, metrics: nil, views: views))
cell.contentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-[promt]-|", options: nil, metrics: nil, views: views))
cell.contentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-[uitextfield]-|", options: nil, metrics: nil, views: views))
One solution that has worked is to set the width of the uitextfield to a ridiculously high number:
cell.contentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-[prompt]-[uitextfield(1000)]", options: NSLayoutFormatOptions.AlignAllCenterY, metrics: nil, views: views))
I can't use this solution however because sometimes the UITextField is a UISegmentedControl (or other control), and I don't want to stretch those controls out.
Why is the UITextField forcing its width to be really small even if I explicitly set frame.size.width to something large?
The UITextField's content hugging priority along the horizontal axis should be lower than your prompt element's content hugging priority.
You can check out the content hugging priority by doing yourTextField.contentHuggingPriorityForAxis(.Horizontal). And set it using yourTextField.setContentHuggingPriority(250, forAxis: .Horizontal). You may also do this in the interface builder (which I prefer).
Try setting the text field's content hugging priority to 250, and set prompt's to 251.
Solution:
1) Pin the UITextField to the right edge of its superview
2) Change the hugging priority of the UITextField to less than 250
Can someone explain why this works? Why doesn't it work to just do step #1? Or, if you only do step #1, why don't prompt & uitextfield expand equally to fill up the extra width in the superview?

Resources