I've been looking at many differnent solutions using size classes and Autolayout and still haven't been able to get a consistent UI on different sized screens. This seems like it would be a pretty trivial thing to do but I'm on my second day struggling with this. I'm developing on the iPhone 7 in my story board, but when I switch preview to other devices the layouts get messed up. Here are two screen shots demonstrating the issue: iPhone7View, iPhone4sView.
What I've tried:
For the App label, I set the leading, trailing, verticle spacing to top layout guide, and verticle spacing from the App label to the email text field.
For the email field I set the leading, trailing, and verticle space to the password field.
For the password field I set the leading, trailing and verticle space to the sign in button.
For the sign in button I set the leading, trailing and verticle spacing to bottom layout guide.
Additionally, I also set the constraint so the email and password fields have the same width and height.
Is it possible to achieve this using only the storyboard, and make the views adapt to the screen size?
I would lower the priority of the fixed constant constraints, and then create another set of more flexible constraints for the minimum spacing that you want.
As an example of what I mean, for the App Name label you would keep the original top space constraint that you have, but lower the priority to, say, 750. You would then create another constraint for the top spacing and make it something like >= 40 (whatever you want the minimum spacing to be), and the priority for this should be higher than that original constraint (i.e. keep it at 1000).
Yes it is possible. Here's what I would do...
For the App label:
anchor to the parent's top layout guide.
center to parent horizontally.
let the text determine the rest.
For the sign in/sign up button:
anchor to parent's bottom layout guide.
anchor to parent's leading and trailing edge.
let the text determine the height.
For password text field:
vertical space to sign in/sign up button
anchor to parent's leading and trailing edge.
fix height.
For the email text field.
vertical space to password field
anchor to parent's leading and trailing edge.
fix height.
In response to your comment, you can't use percents with constraints in storyboard. If you want to use percents, you will have to adjust the constraints in code.
Another option would be to use a stack view. Here is an example:
https://www.dropbox.com/s/d7yfgjvafweqykq/example.storyboard?dl=0
Related
I have a cell in which I place four buttons and four labels. Each button gets assigned a picture with width 50 and height 50. Furthermore, all buttons have a corresponding label describing what they're intended for.
My objective is to have the buttons and labels resize to keep the buttons' and labels' aspect ration intact while the screen dimension changes on different devices. I have been playing with auto layout changing the hugging and compression to achieve this but haven't been successful yet. Any help would be much appreciated...
I think you should take a look at a UIStackView, because this seems exactly as a use case for stack. Just put each pair button/label in a stack, and then all four pairs into a horizontal stack, which you constraint to the cell itself. You should be able to handle all you need just by configuring the stack’s properties (axis, distribution, alignment, spacing).
Embed your button and label into a view. Set the width of this view equal widths to content view and change the multiplier value to 1:4. This will adjust the widths of the views according to superview. Also, set the top and bottom constraint to 0 for this view.
Provide center align y-axis constraint to button after setting the width and height constraint to 50. Set its top constraint to a value you deem fit.
Set labels's leading and trailing constraint to a value like 8. Choose center alignment for text. Also, provide top constraint to buttona nd bottom to its superview.
Copy the view and paste to create the three views and provide them equal widths constraint to the first view. Also, provide their leading, trailing, top and bottom constraints.
Here are a fast tutorial in how to achieve that:
1-
2- completion of the first Gif:
Note you can achieve the same output using a UIStackView
I’ve built a simple login screen layout. In a vertical direction, there is a logo at the top, followed by 2 text boxes for email and password and then a submit button.
There is an outer container which container 2 more container views, one for the logo and one for the text boxes and button.
With auto layout, I have got the layout displaying correctly in Xcode, with the logo container above the input details container. However, when I launch the app on the simulator or on a device, the logo seems to drop down over the top of the text boxes.
Xcode is telling me I am missing a constraint for containerLayout for y position or height. I’m unsure if this has any impact on the problem.
It would be extremely useful if someone could explain why the logo is dropping down. I will include an image of the constraints in place.
As an absolute minimum, you should:
Add leading, trailing, bottom and top constraints to the logo image view.
Set vertical content hugging priority for the text fields to required (1000).
Add bottom constraint for the sign in button.
You definitely use too much of center X, and equal widths, this obscures entire picture of your layout. If you want to make it simpler and more readable include the following modifications.
Remove center X, center Y and equal widths from the logo image. As you will see it won't break anything but only simplify the layout.
For both text fields, remove center X and equal widths constraints.
For both text fields, add leading and trailing constraints to the superview
Repeat last two points for sign in button.
If you are targeting iOS9 or higher you can use a stack view to layout text fields and buttons. Below you can find the final result. Of course, you can introduce a lot more improvements to this layout but I don't want to reinvent it here.
Update
To configure bottom constraint for the logoDetailsLayout just add it as normal. Sometimes when views are not aligned as they should be Xcode gets lost. In this case, you can double-click this constraint and fix it in the attribute inspector.
This is how I configured it.
I'm currently setting up a login screen that should ultimately look something like this:
I've successfully accomplished all the constraints needed to create the desired look on all screen sizes, however, I can not seem to figure out the constraint needed to correctly align the "Don't have an account? Signup". I've designed it so the "Don't have an account?" is a UILabel, and "Signup" is a UIButton. I've just aligned these side by side.
The UILabel, "Don't have an account?", has the following constraints:
The UIButton, "Signup, has the following constraints:
These constraints seem to accomplish what they need to on screen sizes 4" and below. however the 4.7 inch, and 5.5 inch (iPads excluded), have wide spacing between the UILabel and UIButton. I've read Ray Wenderlich's tutorial on auto layout, and still can not figure out the problem (I'm new to auto layout, but I have an idea what I'm doing. I'm not just adding random constraints hoping it works).
This is what it looks like on all my targeted devices:
Notice as screen size increases, so does the gap in between the label and button. Any help is appreciated.
You are setting the leading space of the label to its superview, and you are setting the trailing space of the button to its superview. So obviously if the superview gets wider, they are going to get further apart.
So if that's not what you want, don't do that.
The actual solution to what you want to do is quite tricky. You want these two objects to behave as a group, and you want that group to be centered. There's no simple way to express that. You will need to make a group. In other words, you will need a container view, give that view an absolute width and center it, and put these two objects inside the container.
New in iOS 9, a UIStackView can help you with this.
Another approach that works is to use a couple UIViews as spacers. I sometimes prefer this to containment, but it is probably a matter of taste.
Remove the leading constraint from your UILabel.
Remove the trailing constraint from your UIButton.
Add a UIView with clear background in front of your UILabel. Set a leading constraint from this UIView to the container leading edge with constant 0. Set a trailing constraint to the UILabel with constant 0.
Similarly, add another UIView after your UIButton. Set a leading constraint from this UIView to the UIButton with constant 0. Set a trailing constraint from this UIView to the container trailing edge with constant 0.
Both UIViews will need a Y position and height. These are somewhat arbitrary so I would set Align Center-Y constraints with your UILabel, and height constraints of say 5.
Here's where the magic happens: select both UIViews and set an Equal Widths constraint. This forces the UIViews to occupy equal space on both sides.
UIStackView is overkill for this situation. Just
Put the label and button in a single UIView.
Constrain the label's left and center Y to the container view.
Constrain the button's right and center Y to the container view.
Constrain the label's right edge to the button's left edge.
Set the horizontal content hugging priority of the containing view to 1000.
Constrain the containing view's center X to its superview.
You can do it to your existing code only by setting few constraints. And this would work on all resolutions even on the iPad. You don't need to group them , i have attached the images to show the constraints that i have applied.
And for the button set this constraints
It would be shown properly on all the devices kindly have look as to how it looks on all the resolutions and also in the landscape mode of each resolution
Thanks
Omkar
Everything looks fine in IB. When I run my app using an iPhone5/iPhone6/iPad sims, it's completely mangled.
In IB:
In iPhone6 sim:
In the above sim, the buttons are cut. The textfield and textview are also cut. For the TF & TV, they are aligned center but trail off the edges on both sides.
I have the buttons width set
Editor > Pin > Widths Equally
The title label is set with a
Horizontal Center in Container
constraint
The textfield and textview also have
Horizontal Center in Container
and
Editor > Pin > Width
Is there some way to fix this?
-- EDIT --
After a few tries with constraints, looks like I have everything working except the two buttons.
Current listing of constraints:
As suggested by others, you should consider using the Auto-layout feature if you plan on constructing your views using the IB.
Here are some tutorial links:
RayWenderlich.com Part One
Youtube video This one covers a bit of size clases
Hope they help.
UPDATED:
I've read your updated post, you need to add width and height constraints. The view you see in the IB right now is 600 by 600 points, and the simulator one is smaller, which means that if you leave it as is, when you run the app you'll only see what the iphone screen has the capacity to show.
You need to add more constraints than what you used, try defining an equal width for the buttons, and assign the left one a left margin constraint, the right one a right margin constraint, give both of them vertical spacing constraint related to the text view or long label, the text view or long label should have left and right margin constraints, a height constraint and a top constraint to the textfield, the textfield should have a vertical spacing constraint to the label, also left and right and height constraint, and last the label should have leff, right and height constraints plus a top constraint to the main view.
I feel that those are all you need, but Xcode will through warnings at you if it feels you are missing something.
Try it, and let us know.
I am trying to convert my app to use Auto Layout.
This is how it is supposed to look (before I used Auto Layout):
Now I am unsure how to achieve the following using Auto Layout:
The left text label (with 22:35 in it) must be in the horizontal
center of the KL1032 label when the right label is not present (with
-14 min in it).
If the right label actually is present, then the right edge of the
22:35 label should align with the horizontal center of the KL1032
label and the left edge of the -14 min label should also align with
the horizontal center of the KL1032 label, leaving a little space
between the labels just as in the screenshot.
Which constraints do I need to use for achieving this? Do I also use Content Hugging priority's?
I tried just centering the 22:35 label, which is fine if the right label is empty/not present. But when the right label is present, this of course does not work correctly.
Embed each label in a view and give all the views a minimum width constraint of 14. Then the layout adjusts as you describe when the right label is empty. So, you layout the embedding views:
You're going to have to add and remove the "(-14 min)" label rather than just hide it or set it to be empty.
Set the 22:35 label to be have its horizontal center aligned with that of the KL1032 label, but with a somewhat reduced priority (say 750). Also set a constraint so that the trailing edge is greater than or equal to the center of the KL1032 label minus whatever slight spacing you want. This one should be at priority 1000 (required).
When the "(-14 min)" label should be present, add it and set up constraints on it. Constrain its leading edge to be the trailing edge of the 22:35 label plus the spacing you desire. Also create a constraint to align its center with the center of the KL1032 label, but set its priority to be between required (1000) and the constraint centering the 22:35 label, for example 800. The layout system won't be able to center it because that would force the 22:35 label past its required constraint, but it will get it as close as possible.
When that label should not be present, just remove it from the hierarchy, which will also remove its constraints. The 22:35 label will move back to being centered (because it can and it "prefers" to).
If you prefer, you can do the layout in the NIB with both labels present. Make outlets to the "(-14 min)" label and also the constraints on it. Make them strong because you'll be removing them from the hierarchy temporarily but don't want them released. That way, your code can just remove and re-add them as appropriate, without having to express the constraints in code.
Edit: Oh, and you'll want a constraint setting the baseline of the "(-14 min)" label to be equal to the baseline of the 22:35 label. You'll have to add that each time in code or set it up in the NIB with a strong outlet and re-add it each time, just like the others.
Edit 2: Another approach occurred to me. You could leave the "(-14 min)" view in the hierarchy and all of the constraints in place all the time. When you don't want it to show, set the view to hidden and set the constant of the constraint between its center and the center of the KL1032 label to be a much larger value. Definitely large enough to allow the 22:35 label to take its preferred position of being centered, potentially large enough to be well off-screen.
Since you don't want the 22:35 label to follow it all the way over, the constraint establishing the spacing between those two labels should be made to be "greater than or equal" rather than "equal". This change would not be conditional on whether the "(-14 min)" label is showing. It's just how that constraint should always be.
When you do want the "(-14 min)" label to show, reset the constraint that tries to center it back to having constant equal to 0. Also, of course, unhide it.