Autolayout view dropping down - ios

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.

Related

Swift Storyboard - Centring an Icon and multi-line text horizontally

I am trying to create an Android-esque Snackbar. All the behaviour is correct but I am left with a layout issue. I have actually broken this out into a test app to simplify things a bit.
The bar is pinned to the bottom of the view and contains an Icon (UIImageView) along with some text (UILabel). This text can be up to 2 lines max.
For example, it should be able to exand out like this:-
However to further complicate things, i need it so that the icon and text are centred within the red bar and then spread out from the centre until such point that it needs to wrap. Note that there is a padding to the start of the icon and end of the text to prevent it touching the sides. An example of centred content would be..
I haven't been able to get the correct layout. I think the issue has been trying to centre the two items whilst simultaneously conforming to a width that doesn't exceed the edge bounds, causing a constraint conflict. I have also tried embedding the icon and label in a horizontal stack view but couldn't seem to find the correct fill option whilst centring everything.
I have even tried using NSAttributed string and adding the image to the text itself but when the text wrapped, the icon was being resized and/or misplaced.
As you can see, i have been doing this in Storyboard but i am more than happy to do this programmatically if it serves this purpose better.
Created this Demo for reference , it's a simple task of making a nested view inside the red view with a centerX constraint of priority 1000 and a leading constraint with 999 priority
Now you have this effect

Xcode IB auto sizing?

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.

UICollectionView change flow direction on rotation

Hey, I'd like to obtain what you see in the pictures: in Compact Height mode (landscape iphone) both the red and the blue view have to take all screen vertically and half the screen horizontally. In Compact Width mode (portrait iphone)they have to take all the screen horizontally and half the screen vertically. Space between views should be same size in both modes.
I used to think I have to use size classes and auto-layout constraints, but everything I tried failed miserably.
Maybe I have to use a UICollectionView and change flow direction based on orientation (if that is even possible)?
A collection view is probably overkill, because you don't want scrolling and that's the whole point of a collection view--by the time you do the sizing to stop it you'll have done all the work necessary to set a non-scrolling layout.
This is possible with Size Classes in IB. First, In general you will probably find it helpful to name the views in the Document Outline on the left in IB. You will also want to use this outline rather than try to grab the tiny constraint H-lines.
Set up all the constraints except 1) constraints linking the
OrangeView and BlueView to each other, 2) the constraints linking
the OrangeView to the top and left(leading), and 3) The constraints
linking the BlueView to the bottom and right (trailing).
Change the size class setting at the bottom to w-Compact and
h-Any in the funky box system. Now we're designing for a compact width, so views on top of each other.
Create a constraints for vertical space for BlueView.bottom to
OrangeView.Top. Also create constraint for OrangeView to
superview.leading (or ledaing,margin) and BlueView to
superview.trailing.margin. If you select any one of these constraints and look at the Size Inspector on the right (the ruler) you should see an "installed" checkbox not selected, and below that a w-Compact h-Any and another installed box, this one selected.
Now, while keeping the constraint selected just to see what happens, change the sizeClass selector at the bottom to w-Regular h-Any. Notice that in the Document Outline to the left, it should get grayed out.
Now we are designing for regular, so side-to-side. Add constraints linking the views for horizontal space, BlueView.trailing to OrangeView.leading. Also link OrangeView.top to the superview.top or top aligned to BlueView.top, and same for bottoms. You can manually edit the frame first; if not, IB will automatically fill in the wrong values, so edit these after you create them, and verify they are w-Regular and h-Any. With the ViewController selected, select "update frames" and the views should snap to their expected shape for the size class.
Let us know if this works for you or if it was unclear. Good luck!

How to center horizontally two labels?

I have pretty straightforward requirements where two labels must be centered horizontally. So, I have selected them and chose Editor->align->center horizontally. Then added top space to container constraint to both of them. I also need the labels to shrink/grow regarding content size. However, IB shows errors and several warnings. I could make the labels shrink/grow just by adding pin between them (horizontal space) but they will not be centered in that case. Here are the screenshots:
here are the errors and warnings:
UPDATE theraven gave an interesting suggestion to use dummy view for centering it horizontally and pinning two labels to it. I have removed all existing constraints, added this dummy view and center X + center Y constraints to it. Then pined two labels to it (added horizontal space constraints). However, I still get a bunch of errors and warnings:
UPDATE2 Just updating the question, but still no valid answer found. #Theraven workaround works for iPhone4, iPhone4S, iPhone5 and iPhone5S, however it's not real centering but rather a workaround. Therefore for iPhone6 and iPhone6 Plus it doesn't work as leading and trailing spaces will be fixed and won't automatically resize for larger width.
What you could do is add both labels to another view, like a container view. Then you need to center this one horizontally and add the necessary constraints.
To add the containing UIView, you can select both labels, go to Editor -> Embed In -> View.
Then you would need to add constraints to make the containing view fit the two labels. So something like this:
First Label (left one):
Leading Space to Superview
Top and bottom Space to Superview
Horizontal spacing to the next Label
Second Label:
Trailing space to superview
Top and Bottom to superview (or align top with the first one)
Then the containing view should resize as to fit both labels. Then all you need to do is add the top offset constraint for this container view and a horizontal alignment it in the parent view.
This way, the containing view will grow as much as it needs to fit both labels and the space between them and will always be centered in the parent view.
I took a screenshot of my test constraints in case it helps you more.
Hope this was what you were looking for.
To solve this use a blank UIView in between your two labels and center it horizontally. Then pin the two labels either side of the centered blank view. It is common convention to use spacer views like this in auto-layout.
I really don't like the idea of adding another view just for sake of estethic.
Another alternative is to horizontally-center the left view, and horizzontally space the right view of an amout X with the left one.
Then to give the horizontally-align contraint of the first view a negative value equal to the first view width plus half the views distance. Or use multipliers as said in a previous comment.
But this only works with fixed width views i guess.
Use centered UIStackView as a container for two labels with a spacing required.
I didn't really understand what you wish to do.
The error you get (in the first screen shot) is that you are missing constraint for the x position of the labels.
For UILabel you must have constraint both for y and for x position regarding to the container view, when you selected them both and chose Editor->align->center horizontally, you just say that label1.center.x = label2.center.x.
You still need to say where they will be in the container view, you added the top space to container, so you do have the y position, but you didn't say where the x position should be.
You said
I have pretty straightforward requirements where two labels must be centered horizontally
But where they should be in respect to their container?
thanks
Using spacer views is the best possible solution I could figure out, even though it looks ugly for the developer. The user wouldn't even know what's going on behind the scenes and once you have the spacer UIView, you can always reuse it.

Xcode 4 and Interface Builder: Editing Vertical Spacing Constraint (Anchor Top, not Bottom)

I've got a widget that is not laying out correctly on device (its looks OK in IB, but its not quite right). The widget is a label and its located about mid-screen. Interface Builder gave it a Vertical Space Constraint with a 'Bottom Anchor'. Here, bottom means bottom of the screen (rather than a widget below, or anchor to top screen).
I'm in the inspector, but I don't see how to change to a top anchor (preferably, to the widget above). I tried reading Apple's docs and Editing Constraints in particular, but it was a confusing and did not explain how to make the change (or I missed the discussion - which was 7 sentences).
Below is a screen capture under Interface Builder showing the Vertical Space Constraint anchored to the bottom of the screen. And its attributes leave a lot to be desired - Equal, Constant and Priority don't really help.
Does anyone know how to edit constraints? Specifically, I want to (1) change a vertical spacer's anchor from bottom to top; and (2) anchor against the widget above, and not the top of the screen.
Select the "Embedded" and the "Calculated" element together by shift-clicking.
With those two elements selected, use the constraints menu:
This menu, together with careful selection of elements, is central to happy editing of constraints in IB. In your case, choose the central item, the Pin menu. Choose Vertical Spacing - this will create a new constraint on vertical spacing between your two elements. Alternatively, select a single element and pin "Top space to superview" to pin to the top instead of the bottom.
You can now select and delete the vertical spacing to the bottom of the view. IB wouldn't let you delete this before since you have to have a complete, non-ambiguous set of constraints. After adding your new vertical spacing constraint, you now have this.
To illustrate further, here is an empty view controller, with a single text field which I have dragged on:
All of the constraints are purple, which means IB has added them for me (they are System constraints) and they can't be removed - they are the minimum constraints needed to position and size the text field.
Now, I'll select the text field, and pin the top space to the superview:
Now you can see that the two vertical space constraints have changed to blue (they are now user constraints) and they have a thicker appearance in the editor. This means that one of them can be deleted. I select the constraint for the bottom space and hit delete:
Note that this still has the appearance of a user constraint - but if I try to delete it, IB will automatically recreate the system constraint pinning to the bottom of the superview, getting us back to square one.
I have written about this, and similar autolayout topics, here.
I got one word for Autolayouts. If it works, it works but if it does not, then use the old fashioned way (use code)

Resources