Dynamic width view with subviews - ios

I am trying to create the following in a xib:
https://imgur.com/nyLv65t
Please ignore the poor drawing. Basically, the black border is the main view. Inside that main view, I have a smaller view (in blue) that should be on the right side of the main view, centered vertically. The blue view also has a label as a subview, so I need the blue view to have a dynamic width based on the length of the label.
However, I can't seem to get the constraints right. Every time, I get red constraints and errors. What would the correct constraints for this be?

You need to give below three constraints
Vertically center to it superview
Constant trailing space.
Leading constrain with >= value to specify the value of x
Storyboard constraints:
Download demo code

Related

Q: Auto Layout 4 squares Issue/General Auto Layout Issue

So I'm just trying to wrap my head around Auto Layout; I understand how to use constraints, just not how to apply them appropriately. In the picture below I had set no constraints and simply want this simple design to resize correctly on all size classes (Horizontally and Vertically).
http://tinypic.com/r/2ymxbop/9
What constraints would I need to put in to have these squares resize appropriately on all screens (horizontal/vertical) and can you do this in the ( W:Any H:Any ) size class or do you have to set constraints for each individual size class?
Thanks!
One size class is all you need in this case.
Set a constraint for each of the 4 gaps between the rects (i.e. the space between the top 2, between the top-left and bottom-left, ...).
Set a constraint for each rect to its 2 closest outer edges.
Now you've set four constraints for each rect - and that's all you need!
For that case: follow the steps
1.Add four uiview to screen, two top and two bottom.
2.In your case the view not touching to bottom layout guide,so you have to give fixed height.
Start the add constraints to views.
All views are correct width and height.
3.So take first view from left top,give leading space ,top space and adjecent spacing to right top view. And select the pin button from the canvas below right side option availabe, select height ,give how much height you need.
4.Now select right top view ,give constraint to top layout guide and trailing space.and also same height what you selected before for view one.
5.Now view three ,left bottom view , give leading ,spacing to top view and right spacing to fourth view and select same height .
6.Now fourth view, give spacing to top view ,trailing to container and select height.
Almost completed.
7.Select all views at once ,give equal withs(option available in pin).
lastly some warning will shows ,do update frames.

Using Autolayout adjust vertical position from horizontal center if too high

In the diagram I need to center align the right view with the left view. If the right view is larger than the left view I need to top align it. Can I do this with constraints (storyboard) or do I need to do something in code to adjust the position (via a constraint) of the right view after the size has been determined? The Right view has multiple UILabels that can grow so I don't know the size until runtime. The container is actually a UITableViewCell.
Centering is easy. The right view resizes and the cell adjusts to that size. The issue is the requirement to top align if its too big.
You want this:
You can do it with two constraints.
You want the top of the green view to be greater than or equal to the top of the pink view, always. That is, you require that green.top ≥ pink.top.
In addition, you want the Y-center of the green view to be equal to the Y-center of the pink view, when possible. That is, you prefer that green.centerY == pink.centerY, if it doesn't violate the other constraint.
Here's the first constraint, in the storyboard editor:
And here's the second constraint:
Note that I have lowered the second constraint's priority to 800, which means it's not required but it's strongly preferred.
You don't need to write any code to make this work. I did write code in my demo to wire up the slider and the label, but I didn't have to modify those two constraints from code.
In the storyboard, align the right view to the left view top.
Give the value as
topAlignCons.value= +(leftView.height/2) //in storyboard
so that it gets align to the center of left view
Create an outlet for the top align constraint in your view controller.
When the right view is larger that left view, change the outlet constraint value to 0.
topAlignConstraint.constant=#0;
Now it will be aligned to the left view top with no negative value.

Center multiple UILabels on a line

I want to horizontally center multiple UILabels - as a group - on a line in Interface Builder. One the straight view controller i could not figure out how to do this. I read comments about place the UILabels in a View and then centering the view in the view controller. When I tried this, overtime I said to update frames in the interface builder, the View would be resized down to nothing. (i.e. its height and width would be set to 0 by IB). I need to know how to get this to work in interface builder.
An example of a line containing multiple labels I want horizontally centered is below. The braces simply indicate the start and end of each label and are not art of the text. The <- 6 -> is meant to indicate the trailing space from label 1 to label 2 is 6
Label 1 Label 2
[Rating: 0.0]<- 6 ->[Distance: 125.34 Kilometers]
Any suggestions would be greatly appreciated.
Here is an EXACT example of what I have done and it does not work:
Create a new view controller in IB
Place a page label at the top of the page centered horizontally and aligned to the top of the layout guide.
Add a view with the following constraints on the page:
Now add two labels to the view with the following constraints:
Once this is done I get the following error and updating the frames will cause it to be give a height and width of 0
Here is what the page looks like in IB:
I need the height and width of the view to size automatically so that I have put a multiline label in the view and have all the contents of the view treated as a group and centered on the page.
Any suggestions would be greatly appreciated.
Here is a snapshot of a working set of all the constraints on an abbreviated layout that produces an always-centered view that automatically resizes with the child views (i.e., as the content of any label changes, the view grows or shrinks around it).
Important to your solution, the view has neither a height nor width constraint; its size is constrained entirely by its descendant constraints.
The key is that every component has a direct or indirect constraint from which its size and position are specified or can be inferred. For example, in order for the view to infer its width, the child labels must have a leading space constraint on the first label, a trailing space constraint on the last label, and a horizontal space constraint between interior labels. Those constraints plus the contents of the labels allow the width of the view to be inferred ... and force the view to dynamically conform to that width.
The same applies for the view's height. For example, you can specify the top and bottom space of just one label, or all of them. If just one, the remaining labels can be vertically aligned with it (see "Align Center Y to: Label1" in the screenshot).

Using AutoLayout and ensuring bounds of parent view to fit subviews when resized

I really wish I could get my head around auto layout. It seems that whenever I read an abstract description of how things are supposed to work it makes sense, but whenever I actually try and put it into practise it always causes massive headaches. So, apologies if there is already an answer out there for this but I couldn't find one.
The problem should be relatively simple. I have a container view, which contains two subviews, shown here in hideous colours for maximum readability :) :
The bottom (black) view, should remain at it's current size and maintain the spacing between it and the red view, and the spacing between itself and the bottom of yellow view.
The red view I want to be able to dynamically change its height, causing the black view to shift up/down accordingly whilst the yellow view resizes to fit both the red+black views.
For the black view, I've added constraints to:
Set the height to 94
Pin the leading and trailing space to superview
Set the top space to the red view at 51.
Set the bottom space to the yellow view at 20.
I am trying to understand what seemingly-mystical set of constraints I need to add in order that, when the red view is resized vertically, the black view stays its current distance from the red view and maintains its size, and the outer container view resizes accordingly so that it contains the red view + black view + vertical spacing between the views.
For the red view, I've added constraints to pin the top, left and right spacing to superview, but have had no luck working out the vertical constraints. Currently I've got a constraint pinning the height =114 with a priority of 999 and a constraint with height >=114 with a priority of 1000 thinking this would ensure the view is always at least 114 in height...
The fun starts when I try and manually set the height of the red view.... I've added a button on the view, and when the button is pressed, I manually set the bounds of the red view. (The red view's default height is 114):
CGRect bounds = self.redView.bounds;
bounds.size.height = 300;
self.redView.bounds = bounds;
When I run this and press the button, the view goes from this:
To this:
To me this makes no sense whatsoever. Why does this result in:
The Y origin of the red view changing? Particularly when there is a "required" constraint telling it to stay 20pts from the top of yellow view.
The spacing between the red and black views breaking down, even though the constraint on the spacing between them is "required"?
The vertical size of yellow view not changing. Again, despite the spacing between red+black, and me having tried just about every combination I can think of in terms of compression resistance and content hugging priority.....
I really want to understand this, so would be really grateful if someone can explain what additional constraints / changes to constants are required, but more importantly WHY they are required, because to me it doesn't seem clear at all how the layout system comes up with its answers....
Any clarification much appreciated.
Thanks in advance
(All code above is running on iOS 7 and built with Xcode 5.0.2).
You don't need any fancy constraints to do what you want here -- no inequalities or messing with the priorities. In addition to the constraints to the sides, the red view should have 20 to top, 51 to black view, and a height constraint of 114. The black view, has a 20 to the bottom and a height of 94. The superview (yellow) should have zero constraints to top, left and right -- no height. You should have an IBOutlet to the red view's height constraint. When you want to change its height, modify its constraint (don't set frames):
- (IBAction)resizeYellowView:(id)sender {
self.heightCon.constant = 300;
}
Everything is linked together from the top of the yellow view to the bottom with fixed values, so the only thing that can change when the height of the red view changes, is the height of the yellow view.

Views are Horizontally and Vertically Ambiguous with complex layout

I have a UIViewController on my storyboard that has 2 subviews side-to-side horizontally. I added constraints to fix the leading and trailing edges to a constant (20 pts), and another constraint to keep the widths equal. If I assume the following, it should be possible to calculate what the width of each subview will need to be:
the subviews do not overlap
there are no other views present (horizontally, at least)
the width of the screen (the superview) is known
However, XCode gives me a warning that my views are horizontally ambiguous. I'm guessing that means that XCode is not making one of these assumptions, but which one is it? And is there a way for me to instruct XCode to make that assumption?
EDIT: Okay, played with it a bit and got the warning to go away, but it looks like it's not making the first assumption - it's just setting each subview's width to superview.width - 40, and happily burying one view underneath the other. So the question is how to I stop them from overlapping?
EDIT 2: Okay, my actual screen is a lot more complicated than my simple example. Here's what I got:
So in this setup I have 4 views that are vertically and horizontally staggered.  I want the blue, red, and purple views to all be the same subview.frame.size.width = superview.width - 60. The blue and purple are lined up in the left column, and the red is alone in the right column, and all the gaps (between the two columns and between each column and it's nearest edge) are at a constant (20 pts). These 3 tables have a variable height, which I will be setting programmatically as described in James's answer here. At the bottom is a pink view that stretches the width of the screen (minus gaps), and sits at a constant 20 pts below either the purple or the red view, whichever is lower (which I'm attempting to do by giving it a spacing constraint of >= 20 to each view, and I hope that it will pick exactly 20 for one of them). Since all of the heights are dynamic and may not necessarily fit on the screen at the same time, I made their superview a UIScrollView instead of the normal UIView.
When all is said and done, I'm still getting a warning that all 4 of my views are horizontally ambiguous, and that the pink bar is vertically ambiguous. I think it's having trouble realizing what is supposed to go next to what, which is why it thinks it's horizontally ambiguous. And I think it's not picking to place the pink bar exactly 20 pts below either the purple or red views, which is why it thinks it's vertically ambiguous. Can anyone confirm or deny any of these suspicions? Or suggest a way around it? When I run it in the end, I just get this (I made the background of the scroll view yellow, which you can't tell in the storyboard screenshot):
Vertically Ambiguous
Okay, I think I've solved the vertical ambiguous part. I added two vertical constraints between the pink and purple views and two vertical constraints between the pink and red views. For each pair, the first constraint is that the spacing between them must be > 20 pts, and it has 1000 priority. The second constraint is that the spacing is = 20 pts, but it only has an 800 priority.
For example, if the bottom of the purple view ends up being lower than the bottom of the red view (as it is in my first screenshot), Xcode should try to set the vertical distance between the pink and red views = 20, but it will realize that that conflicts with condition that the space between the purple and pink being >= 20. Since the >= constraint has higher priority, the = constraint will be ignored. Now, when Xcode looks at the constraint that the spacing between the purple and pink views being = 20, it checks that against the constraint that the pink and red must be separated by at least 20. Since the bottom of the red view is higher than the bottom of the purple view, the >= 20 constraint between the red and the pink still passes.
So TL;DR, you can set up a view to have a spacing at a given value (x) from the most extreme of multiple views by giving it a >= x constraint with 1000 priority and giving it a = x constraint with <1000 priority for each view you are considering - and my vertical ambiguity problem has been solved. I do not yet have a solution for the horizontal ambiguity for all 4 of the views.
Horizontally Ambiguous
Okay, I got the horizontally ambiguous part fixed now as well. What it boils down to is that constraints in scroll views (and therefore table views) work differently than they do for any other kind of view. Here's what the step-by-step looks like.
Place the UIScrollView
Place a UIView into the UIScrollView to serve as a "contentView" for that scroll view
Add constraints to pin the contentView to all 4 corners of the scroll view AND pin it's width and height (so 6 constraints between the contentView and it's superview - 2 more than usual). Note that the width and the height can be pinned to something much larger than the normal screen size, which is probably why you are using a scroll view to begin with.
Add all of your other views you want in the UIScrollView (UIButtons, UILabels, etc. - I'm just going to assume UILabel from here on so I don't have to type as much, but any kind of UIView subclass will work) as subviews of the contentView, NOT directly as subviews of the UIScrollView
With this setup, the UILabels that are given constraints to their superview will constrain to the contentView, which has a defined size, so nothing is ambiguous.
Alternatively, if you want to fix the sizes of your UILabels (or dynamically calculate them, depending on the functionality of your app) and let the contentView expand to hold them:
Place the UIScrollView
Place a UIView into the UIScrollView to serve as a "contentView" for that scroll view
Add constraints to pin the contentView to all 4 corners of the scroll view AND pin it's width and height
create an outlet for the width constraints on the contentView (let's say we name it contentViewWidthConstraint)
place the UILabels
fix the sizes of the UILabels
create an outlet for the width constraints on the UILabels
Then in the code for viewWillLayoutSubviews
add up the widths of all of the UILabels and any gaps you want between them (as a CGFloat, which I'll call totalWidth)
set contentViewWidthConstraint.constant = totalWidth
And you're good to go! Note that I assumed you were setting the width in most of this example, but it should be just as applicable to height.
The problem is that many different widths of the two views will satisfy the constraints that you've set up. Here are two examples (I drew the shapes stacked vertically to make it easier to see the overlap example):
You can add a horizontal space constraint with a value of 0.

Resources