evenly spacing 4 or 5 buttons, depending on the user device - ios

I am trying to create a user interface for both iPad and iPhone in storyboard. The iphone version has 1 button less. All buttons and helper views are pinned to the bottomLayouGuide. Also, I am using hidden helper views to evenly split the buttons. Hidden helper views have equalWidth Constraint active and each one is pinned to the left and right button. The result of this restrictions is the bottom image showing the ipad version
The problem arises when I want to eliminate 1 button and still have my button evenly split. Is there variation of the approach described earlier to achieve evenly spaced buttons even if 1 button is missing? If not, what approach do you recommend for evenly spacing 4 or 5 buttons, depending on the device running the app?. The only think that must be satisfied is that the buttons are pinned to the bottom layout guide, because of animations applied to them in the app.

The key here is to restrict the installation only to certain layouts.
The way I would do this is to first put the view in the compact width, any layout.
Then layout the buttons and positioning views for the iPhone.
Then set the layout for regular width and any height.
Install all the buttons, views and constraints except for the one that pins the last view to the end of the main view.
Then add the 5th button and an extra view with the required constraints to pin it properly.

Related

How to make controls occupy the real size inside a stack

I have an horizontal stack with three controls.
The first two (green and orange on the figure below) are based on IB_DESIGNABLE UIView classes. There are no width constrains inside these classes relatively to the width these controls have to be. The third view is a regular UIView.
These controls have multiple buttons. The buttons represent values for configurations. They are radio buttons used to let the user select a particular configuration between multiple. Because these buttons are used multiple times, a particular configuration may have just 4 options to choose, so I have to hide 3 buttons, in other cases 2 and so one.
These IB_DESIGNABLE classes are based on XIBs. The Buttons are inside horizontal stacks inside these XIBs.
This is the problem. Suppose I have to hide 2 buttons on the green one. Because both are inside a horizontal stack and their buttons are also inside an horizontal stack, when I hide one or more buttons from each one, I want the control to reduce its width.
In that case, by hiding 2 buttons of the green one I want the whole thing to be rendered like
But it is not. It is rendered like
NOTE: when the controls contract I need the third view to occupy the remaining space. I use that view to force the controls to the left, because I was unable to do that using just the stack, that were always trying to expand the whole thing.
None of these 3 views have constraints.
The buttons inside the XIB have horizontal constrains of width but they are using a priority of 750 instead of 1000.
The stack that holds the controls is horizontal, fill, fill, spacing 20.
The stack that holds the buttons inside the xib is horizontal, fill, fill, spacing 0.
Any ideas?
How do you hide the buttons? By isHidden=true? Then thats the reason. Autolayout ignores hidden state. The buttons are still there. You have to deactivate/change the constraints of the buttons too. e.g. set width constraint of the buttons to 0.

What must I do to add a constraint to a view in a Storyboard launch file?

I added a Storyboard launch file to upgrade a project from iOS 4 to iOS 9. The app runs in the Simulator but nothing I do will centre views for iPhone5 and iPhone 6 or scale them to fill the frame. Instead they look like bonsai versions of an iPhone 4 pinned in the top left of the screen.
When I try to add constraints to centre the views by following the procedure described here, the menu will not give me options to choose the view I need to constrain.
Instead I get this.
The bottom two - Horizontally in Container and Vertically in Container - are the only options I can check. But pulling down on the arrow to the right of the text box only gives some of the options needed to Add Constraints
What do I need to do to enable the view option ?
EDIT 1.
And furthermore, when I try to constrain width and height I get this
All six options are in grey and none of the text boxes change
EDIT 2.
And using the Size Inspector to look at the view I am trying to centre and fill, the view has no constraints as shown below.
It is really starting to look like there is no simple way to launch an old app where views have been created programmatically and have Storyboard Launch automatically layout views to suit different iPhone screen sizes.
The "Horizontally in Container" and "Vertically in Container" checkboxes affect individual views. The are "binary operations". If you select more than one view, these checkboxes cause all the views to be centered in their container.
In contrast, the other checkboxes in this popup align groups of views.
If, for example, you select 4 views and click "leading edges" then it creates a set of constraints that line up the leading edges of all the selected views. (Under the covers it creates enough pairs of constraints to line up all the views by their leading edges.)
If you only have 1 view selected then only the bottom 2 checkboxes ("Horizontally in Container" and "Vertically in Container") are meaningful and the others are dimmed. As soon as you select more than one view the others should be enabled.
I had the same problem because on Show the Size inspector > Layout, "Autoresizing Mask" was selected, by changing the value for "inferred (Constrains)" it will resolve this problem
illustration
Select the view you would like to constrain. Then tap the button to the right of the one you have selected and use that menu to define your autolayout constraints. If you want it to work for all devices make sure your storyboard is on the wAny hAny size class setting.

iOS multiple screen not working?

I just started iOS programming and I want to make a login screen. I want to align center horizontally the everything on all devices like the iPhone 5 and iPhone 6 and iPhone 6 Plus but it's not working. I just put the elements on the screen. Anything else i need to do?
There are a few ways you can do this...auto layout as #ozgur said is your friend.
what I would do is throw them into a Stack View
To do that tap each horizontal group so for example "username" label AND the text field to the right and while they are both selected tap the icon at the bottom right that is on the left of the 4 icons (it has a downward arrow)...now do the same for the password...now do the same for the login button...now select all 3 stackviews and tap stackview again...
NOW....on the left navigation select the topmost stackview and then again on the bottom this time tap the small icon to the right of the stackview button...to make it simple and in the center tap horizontally in container and vertically in container then add the 2 constraints....
you will also need a height and width so now once more with the whole thing selected tap the |o| looking icon to the right...now give it the height and width you like but before you tap add 2 contraints at the bottom of that menu is a drop down menu..tap it and select "update all frames in container"
that should do it
Use AutoLayOut Constraints to fix your issue.
Contraints will set the spacing with the view.You have to apply it on every single element of your view.
if you only want every thing in center no different spacing for different iPhone use stack View. it will provide the best solution for you.
stackView means collection of your objects. it act as group of your elements so only apply constraints to your stackview.
Rule of thumb is to use Stack views and then use auto layout. Just put the Username and the text field in a stack view (horizontal stack view), same for the other) and then apply necessary spacing and/or autolayout constraints.
You need to learn how to work with Autolayout (I read you just started) and it could be hard concept to grasp at first (it was for me at least) but with practice, you'll master it.
If you do not use the stack view, you need to learn auto layout and size class for adapting the screen.
auto layout began in iOS 6, sizeclass began in iOS 8.
Here is the official apple documentation, to study it. https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/AutolayoutPG/

Auto layout space between elements relative to screen height [duplicate]

I understand the old Struts and Springs method of aligning, sizing and distributing views in Interface Builder. However, I cannot seem to figure out how to evenly distribute views using auto layout with Xcode 5. There was a way to do it using Xcode 4, but that option is gone.
I have 7 buttons arranged in a vertical stack. On a 3.5" layout, it looks great. When I preview the screen in the 4" layout, all of the buttons remain tightly packed and there is a large amount of space below the last button.
I want them to stay the same height, but I want the space between them to be able flex so they can spread out across the screen.
I've been able to get the height of the buttons to flex and fill the space, but that is not my desired behavior. I would like to learn how to use Auto Layout to replace my old Springs behavior, but I can't seem to find any way to do it through Interface Builder.
I'm ok with the top button either being a fixed space from the top edge or a proportional space from the top edge, likewise for the bottom button and the bottom edge. Those are less important to me, I'm good with either.
But I really need to figure out how to evenly distribute the extra space between each of the items in the view.
EDIT Note that in iOS 9 this technique will become unnecessary, because a UIStackView will perform distribution automatically. I'll add another answer explaining how that works.
How to Perform Even Distribution Using Autolayout
The simplest way to do this in Interface Builder alone (rather than constructing constraints in code) is to use "spacer" views:
Position the top and bottom buttons absolutely.
Place spacer views between all the buttons. Use constraints to position them horizontally (centering them horizontally is simplest) and to set their widths.
Make constraints between each button and the spacer view above and below it, with a Constant of 0.
Now select all the spacer views and set their heights to be equal.
The first screen shot shows me setting this up in IB:
I have deliberately not corrected for the "misplaced views" because I want you to see what it looks like while I'm designing the constraints. Here's the result on both a 4 inch and a 3.5 inch screen:
I have left the spacer views black, just to show you how this technique works, but of course in real life you would make them transparent and hence invisible! So the user sees just your buttons, evenly distributed on either height of screen.
The reason for the use of this technique is that although the notion of equality performs the distribution of values you are asking for, constraints can apply equality only between aspects of views; thus we need the extra views (the spacer views) so that we have things we can make equal to other things (here, the heights of the spacer views).
Other Approaches
Obviously, a more flexible approach is to assign the constraints in code. This may sound daunting, but there's a lot of third-party code out there to help you, such as this sort of thing.
For example, if we have a (possibly invisible) superview whose height acts as a boundary to dictate maximum vertical distribution of our four buttons, we can pin their tops to the vertical center of that superview with a constant of 0 but a multiplier of 0.000001, 0.666667, 1.33333, and 2.0 respectively (if we have four buttons); now the buttons will stay vertically distributed even as the superview changes size in response to screen height or whatever. [In Xcode 5.1, it will be possible to set that up in Interface Builder, but in earlier versions of Xcode it is not possible.]
In iOS 9 / Xcode 7 this problem will be trivially solved in IB. Simply select the buttons (or whatever it is you want to distribute vertically) and choose Editor > Embed In > Stack View. Then you simply configure the stack view:
Provide constraints that position and size the stack view itself. For example, pin the four edges of the stack view to the four edges of its superview.
Set the stack view's attributes. In this case we want Vertical axis, Fill alignment, Equal Spacing distribution.
That's all! However, you may be curious about how this works, because it is still possible to do the same thing manually in code. A stack view performs distribution, not by inserting spacer views, but by inserting spacer guides. A guide (a UILayoutGuide) is a lightweight object that behaves like a view for purposes of layout constraints, but is not a view and therefore doesn't have to be made invisible and doesn't carry any of the overhead of a view.
To illustrate, I'll do in code what the stack view is doing. Presume we have four views to distribute vertically. We assign them constraints for everything but their distribution:
They all have absolute height constraints
Their left is pinned to the superview's left, and their right is pinned to the superview's right
The top view's top is pinned to the superview's top, and the bottom view's bottom is pinned to the superview's bottom
Now, presume we have references to the four views as views, an array. Then:
let guides = [UILayoutGuide(), UILayoutGuide(), UILayoutGuide()]
for guide in guides {
self.view.addLayoutGuide(guide)
}
NSLayoutConstraint.activateConstraints([
// guide heights are equal
guides[1].heightAnchor.constraintEqualToAnchor(guides[0].heightAnchor),
guides[2].heightAnchor.constraintEqualToAnchor(guides[0].heightAnchor),
// guide widths are arbitrary, let's say 10
guides[0].widthAnchor.constraintEqualToConstant(10),
guides[1].widthAnchor.constraintEqualToConstant(10),
guides[2].widthAnchor.constraintEqualToConstant(10),
// guide left is arbitrary, let's say superview margin
guides[0].leftAnchor.constraintEqualToAnchor(self.view.leftAnchor),
guides[1].leftAnchor.constraintEqualToAnchor(self.view.leftAnchor),
guides[2].leftAnchor.constraintEqualToAnchor(self.view.leftAnchor),
// bottom of each view is top of following guide
views[0].bottomAnchor.constraintEqualToAnchor(guides[0].topAnchor),
views[1].bottomAnchor.constraintEqualToAnchor(guides[1].topAnchor),
views[2].bottomAnchor.constraintEqualToAnchor(guides[2].topAnchor),
// top of each view is bottom of preceding guide
views[1].topAnchor.constraintEqualToAnchor(guides[0].bottomAnchor),
views[2].topAnchor.constraintEqualToAnchor(guides[1].bottomAnchor),
views[3].topAnchor.constraintEqualToAnchor(guides[2].bottomAnchor)
])
(Obviously I could make that code cuter and shorter using loops, but I have deliberately unrolled the loops for clarity, so that you can see the pattern and the technique.)

Vertically spread/spaced screen elements using Autolayout and Interface Builder

I have a relatively simple portrait-only UI, laid out in a Storyboard, with items which I want to vertically spread to fill both 3.5 inch and 4 inch screens.
In other words, I want the spacing between the controls to be adjusted so that the UI nicely fills the screen, irrespective of the screen form factor.
This doesn't seem like an unusual thing to want to do, however I just can't get Interface Builder (within Xcode 5) to add the right constraints - I only seem to be able to get it to add fixed vertical space constraints, which do not adjust for different screen sizes.
Does anyone know how to do this without resorting to programmatic UI construction? I've invested a lot of effort in getting the Storyboard-based UI just right.
The solution needs to work on both iOS 6 and 7. Thanks!
How to do this depends on exactly what kind of adjustment you want when the screen size changes. One way to do it to give the top and bottom most views vertical spacing constraints to the top and bottom of the superview, respectively. Add a view, I usually use a UILabel with no text, in between all the views you have stacked vertically, and give them equal heights to one another. Give one of those "spacer" views a fixed height, but edit it so its priority is less than 1000 (which means it's not mandatory that it be satisfied). Then add spacing constraints between each nearest neighbor above and below each "real" view and the "spacers", so that you have all the views from top to bottom connected together by vertical spacing constraints. When the screen size changes, the only thing that can change will be the height of the "spacers", since the priority is less than 1000, and all other constraints are mandatory. My constraints look like this:
The labels each have the standard (8 point) spacing to the "real" views above and below them. The top and bottom views should have whatever spacing you want to the screen edges.
Apple have now posted a document which describes the officially-endorsed approach to solving this problem:
https://developer.apple.com/library/ios/documentation/userexperience/Conceptual/AutolayoutPG/AutoLayoutbyExample/AutoLayoutbyExample.html#//apple_ref/doc/uid/TP40010853-CH5-SW8
Summary of the approach: insert spacer views between your controls, which have equal width/height (as applicable) constraints.

Resources