Say I have 2 views (labels or textfields) with varying heights positioned above each other (not on top). I would like the group centred vertically in the superview.
I know I could use a dummy spacer view above and below and set equal height in storyboard. I'm no expert, but this doesn't seem right to me.
Can it be done in storyboard by setting the top constraint for the top view equal to the bottom constraint of the bottom view?
If your subviews' heights will change at runtime (either because you change the number of lines of text in them, or because you support Dynamic Type like a good iOS app should), then no, you cannot do this with just constraints. You either need an extra view or you need to change the constraint constants from code. If you go with an extra view (which I recommend), you can do it with a single extra view.
The simplest solution, if your deployment target is iOS 9 or later, is to put your subviews into a vertical UIStackView and center the UIStackView in the superview. You might not need any constraints directly on the subviews depending on the layout you want.
If you can't use a stack view, you can use a spacer view. First, set up vertical spacing constraints between your subviews to glue them together with whatever padding you want. Then add a spacer view next to the subviews. Set the spacer view to hidden. (Hidden views still participate in layout.) Constrain the spacer's top edge to your top subview's top edge, and constrain the spacer's bottom edge to your bottom subview's bottom edge. Then constrain the spacer to be vertically centered in its container (which should be the superview).
You also need to add horizontal constraints on the spacer to keep Xcode from complaining, but the horizontal size and position don't really matter since the spacer is hidden. So just put it somewhere convenient.
Here's the final set of constraints and layout:
The spacer is the skinny pink view.
You can achieve it easily via center vertically, control and drag the object you want to centre in Storyboard, choose center vertically in container. This way you can centre these subviews in superView individually. If you want to centre these subviews together, you can create another containerView to contain these views(labels, textFields), then centre the containerView in superView.
Hope this help:-)
Control and drag in Storyboard
Center three subView individually.
Center them together with a container view
Related
I've been trying to center some buttons in an horizontal UIStackView
But doesn't matter what I do, the only not broken layout that I can get is basically:
I added constraints to fix the button width programmatically, as the amount of buttons is variable, but can't find a way to fix the spacing between them.
These are the stack view settings:
I tried all the distribution options!
The layout in the top image can be achieved as follows:
Add a stack view with default properties (horizontal axis, fill distribution). Add optional spacing as you want.
Constrain the stack view vertically to its superview.
Either don't constrain it horizontally to its superview, or if you want, constrain it using inequality (left >= superview.left, right <= superview.right).
Center your stack view horizontally within its superview.
Add your subviews. Make sure they know how to size themselves (either based on their own contents, or with a fixed width).
The key is the constraints on the UIStackView in 3 & 4. You're horizontally pinning it to its superview, so it needs to figure out how to fill out all the space. Instead, center it horizontally, and allow the stack view only to take up as much space as it needs.
I am creating a UIScrollView from xib, in which 3 view are there 2 UIViews and in middle an UIImageView. when I am setting constraints Xcode asked to set Y position constrains. But the problem is Y position constraint is blocking Scrollview to scroll down and automatically adjusting the views which looks ugly in landscape mode.
when I am delete that constraint it ask to fix height of subview. I searched a lot but I am new in autolayout so not understanding many of solutions. any help would be great.
You have to set all the height constraints in the content view.
But you also want the height of the Content to be proportional to the screen size.
To do this assign the height constraint of the imageview [equal|proportional|a-computation-of] to the view containing the UISCrollView.
It seems weird to skip levels of herarchy when assigning constraints between two views whose are not direct ancestor/sibling of each other but within a scrollview (at least) it is perfectly acceptable.
You are basically telling the scrollview that it's content has a known size and at same time setting this content to adapt dinamically to the screen size (if the constraints of the root uiview are set correctly)
UIView1
|---UIScrollView
|---UIView2
|---UIImageView [heightConstr.constant=UIView1.height-UIView2.height-UIView3.height-margins]
|---UIView3
This is the basic idea, to be done programmatically, then you can explore other solutions.
Unfortunately the constraint system in ios pretty much sucks when it's up to more complex equations involving more views for a single constraint.
UIScrollViewcan be tricky when adding constraints. You should always add a subView that will behave as the content view for your UIScrollView and all your subsequent views will go inside this content view.
UIView1
|---UIScrollView
|---UIContentView
|---UIView2
|---UIImageView
Set your UIScrollViewconstraints as you would normally but set your content view to have leading, trailing, top and bottom to the UIScrollView but also add two more constraints which will be equal width and equal height to the viewController.view but will have a low priority (So that whichever direction your content will increase in, that constraint will break and automatically increase the content size of the scroll view by taking in the inferred height of the content view). Now go on and add constraints on all your subview as you normally would. Which i'm assuming would be:
Your topmost view will have top and leading and trailing to its superView and also a fixed height.
Your bottom view will have leading, trailing and bottom to its superView and also a fixed height.
Your UIImageViewwill have a leading, trailing and top to top most view and bottom to the bottom view.
Edit:
Here is the screenshot just in case (To show the view hierarchy with the content view's constraints in the inspector)
My problem is slightly different from other's 'Swift UIScrollView' problems when using auto layout:
Problem:
Unlike others, when I run my app, it scrolls. My problem is that the scroll cuts off the bottom 20-30% of the content. I can pull to see the buttons did build and are down there, but when I let it go the scroll snaps back to a false bottom which cuts off my content!!! I've been trying, for days, to fix it to scroll the entire height but it continues to cut off!!
Description of app:
I used auto layout to layout 6 buttons and labels. Each button a rectangular image, with a label directly beneath it. (sorry, the site won't let me post pictures!)
I have my views arranged like this:
MainView > ScrollView > ContentView > Buttons & Labels
I have my contentView pinned to my ScrollView and my ScrollView pinned to my MainView. My buttons and labels all have constraints that are building correctly, to create a list that looks like:
Rectangular button
Label beneath it
Spacing
Rectangular button
Label beneath it
Spacing
Etc.
Can anyone tell me why I can't scroll the full length of the view?
Your description of how your items are constrained is vague, so I'm going to list all of the constraints you need to make this work. Then you can compare what you have to what you need and adjust accordingly.
Your ScrollView should be pinned on all 4 sides to the MainView. (This isn't absolutely necessary. You can constrain your ScrollView however you want, but make sure it can grow as the device and/or orientation changes).
Your ContentView should be pinned on all 4 sides to the ScrollView with offsets of 0.
Since you want your ScrollView to scroll vertically only, constrain the width of the ContentView to the width of the ScrollView using an Equal Widths constraint. To do this, in the Document Outline view, Control-drag from your ContentView to your ScrollView and select Equal Widths from the pop up.
The height of ContentView will be set by the sum total height of everything in it. In order for this to work, your topmost button needs to be pinned to the top of the ContentView, all of your buttons and labels should be pinned to their nearest neighbors, and the bottommost label should be pinned to the bottom of the ContentView. In addition, all of your buttons and labels should have constraints for their widths and heights. I would suggest setting an explicit width constraint and explicit height constraint for your buttons and centering them horizontally in the ContentView. For your labels, set an explicit height constraint and pin the left and right edges to the ContentView.
If you have these constraints and no other ones, your ContentView will be properly sized.
Using contentView, like you said, usually fixes the issue. So chances are you need to take a second look at your contraints. Maybe try this solution in a clean/new project to see that it works. (it does work). My guess would be that some of your constraints conflict each other.
Otherwise I think it would be a good idea to setContentSize of your scrollView in your viewDidLoad.
Another hack would be to place 2 UI objects with their alphas set to zero on the right top corner and left bottom corner. This would hint scrollView to set its contentSize.
I am struggling to align 5 items in a row using auto layout as shown in the storyboard.
I can align the 3 items highlighted below but the 2 inbetween just don't want to align.
I have tried pinning the items to the buttons next to each of the items and setting the size but they refuse to align properly. Have also tried setting the 2 misplaced buttons to the leading and trialing container as shown below but these still do not align properly (or even closely).
Am I doing something wrong?
The way to do this is with spacer views. You need to add a UIView between each of your views and give them each horizontal spacing constraints to the view on either side. You'll need to edit these constraints so they are between the spacer's leading or trailing edge, and the view's centerX (the constant value should be 0). Give the spacers equal widths (but no fixed width), a fixed height, and a clear background color. You views on the left and right sides should have constraints to their closest edge, but the center view shouldn't have a centerX constraint (it's not needed). This will cause the views to be equally spaced in all screen sizes, and in both orientations.
Your best bet might be to create another superview (UIView) within which your button items are located. Then you can align your buttons more fluidly within that superview that encapsulates only those buttons rather than just wrestling with the constraints within the card superview, which it seems you are doing. Just make the background of that UIView clear, place the buttons on it, and it will appear exactly the same and you'll have a better way to anchor your views. This could also come in handy when you're targeting the functionality of just those buttons so you can grab them from the subviews of the button bar superview.
I am attempting to layout a screen design using constraints (auto-layout) from interface builder and hope to avoid coding constraints, but I would accept an answer for either case I guess.
I have two subviews in a contained in a top level view. I want to fix vertical distance of the first subview to the top of the screen (I was able to accomplish that - common use case for a vertical space constraint). I want the second subview to float (vertically) in the center of the distance between the bottom of first subview and the bottom of the screen. The idea is that the design responds somewhat to iPhone 3.5" vs 4" dimensions.
I am having trouble defining a constraint or set of constraints that would accomplish this.
I have tried setting inequalities on the vertical spacing constraints between the second subview and the top of it's neighbor (the first subview) and the bottom of the superview, and playing with the priorities of those constraints.
An idea that was suggested in a few other related posts on SO is to use a container that is pinned to the bottom of the screen, as well as the pinned to the bottom edge of the first subview, and then center my second subview in the container. I was hoping to avoid complicating the view hierarchy if possible, but maybe that isn't easily avoided.
Any thoughts or suggestions?
UPDATE
This answer describes how to do this in Xcode 6.0 (and probably works in Xcode 5.0 and 5.1).
ORIGINAL
If you want to do this with auto layout, you have to add at least one spacer view. It doesn't have to be the superview of the vertically-centered view (or any other view), so it has a pretty minor effect on your view hierarchy.
I recommend not trying to set up constraints in Interface Builder in Xcode 4.6.3. It's just too painful. But if you really must, this is doable.
Create a spacer (a plain old UIView) from the bottom edge of the top-hugging view to the bottom edge of superview. Set it to hidden. Give it constraints to the top-hugging view and the left and bottom edges of the root view, and pin its width. My spacer width is 10:
Add your middle view (here, a button). Give it a “Horizontal Center in Container” constraint. Then select both the middle view and the spacer view and give them a “Vertical Centers” constraint:
Note that if you drop the middle view when IB is showing the correct guidelines, it will set these constraints for you.
You can test by enabling resizing for descendents (but not siblings & ancestors) and resizing the root view in IB. The middle view will remain centered between the top-hugging view and the bottom of the superview: