I have four UIButtons in a parent view, next to each other. The leftmost and the rightmost one will always be smashed into the sides of the parent view, but I'm not sure how I should approach positioning the middle two buttons with constraints.
What I want it to look like:
______________________
[b1] [b2] [b3] [b4]
______________________
With regular constraints on x and y I'm able to place b1 and b2 on the right place, but b2 and b3 requires some magic.
By using constraints on them, telling them to stick to each side, it would look like this in landscape(or on bigger screens):
______________________________
[b1] [b2] [b3] [b4]
______________________________
Without equal spacing. What I need is something like the 'flexible space' which is used for UIBarButton's, but in a regular view. As I can't find anything like that, I'm guessing there's some constraint-magic I need to understand.
I COULD make the buttons big enough so that they are all constrained together (so b2 and b3 are touching, and they all have equal width), but I don't want that. I guess a solution could be to create four ´container´-views in those sizes (big enough to touch each other) and simply place each button in the center of each UIView. But is that really necessary? Feels like such a waste..
You could add UIViews where the three flexible spaces need to be:
–––––––––––––––––––––––––
[b1] * [b2] * [b3] * [b4]
–––––––––––––––––––––––––
Then for each of the spacer views (denoted by *), add constraints such that the trailing and leading spaces are 0 and give them a constant height. Finally, add a another constraint to make all of their widths equal. That way, the spacing between each button will always be equal regardless of the width of the screen. Then you can just make the spacer views transparent so they don't appear in your layout.
Related
In my app for iOS 8, I have a UISegmentedControl that stretches to fit the width of the device's screen. So on an iPad it's more pixels wide than it is on an iPhone 6+, which is more pixels wide than the iPhone 6, etc.
Centered just beneath each segment of the UISegmentedControl, I have a UILabel. So there are 5 segments and 5 UILabels. Each UILabel has a fixed width (fixed by constraint). However if the display size increases they become uncentered.
How in Interface Builder can I specify a constraint that will force each UILabel to become centered beneath each segment? I would be happy if I could just get the elements to remain proportionally spaced with each other as the display size scales, but I can't figure out how to do that, either.
All I can seemingly do is to center the middle UILabel directly under the middle segment by specifying a Center X Alignment between that and the UISegmentedControl.
I specified a Horizontal Space constraint between all the UILabels, and between the outer UILabels and the edges of the view, and set all these to "greater than or equals". They all have the same priority, but strangely, they don't all scale proportionally to each other.
The resulting problem is that the amount of Horizontal Space between each of the UILabels does not scale smoothly as the width of the device's screen increases. If I align everything to be in the proper positions on the iPhone 5S width of screen, then on the iPad their alignment is all wonky, and only the middle one lines up with its segment. The rest of them are all off center.
It appears that there is no way to specify a percentage of the over-all display width as a constraint -- you can only specify things in terms of pixels. Really?!?!
Clearly I could make the width of the objects to be flexible, but because they are text labels with right-aligned text, that screws everything up.
Surely I'm missing something here... since the point of Auto Layout is to make your interface scale according to the screen size, surely there is a way to specify a constraint as a percentage of any given view or subview... surely!!! But how? I've read the documentation and I cannot, for the life of me, figure it out.
BTW I did see that in the past, people have used crude hacks like spacer views or multiple sets of constraints, but surely those are outdated answers, and I'm just overlooking something extraordinarily obvious... right?
You can do this by making the centerX constraint of your labels equal to the superview.trailing times 0.1, 0.3, 0.5, 0.7, and 0.9 with constants of 0. To make these constraints, add your 5 labels to the view. Give the left most one a vertical spacing constraint to the segmented control. Select all 5 labels and give give them a "vertical centers" alignment constraint. Now control-drag from each label to the right side of the screen, and select the "Trailing space to container margin" constraint. Edit each one of these trailing constraints to look like this (except for the multiplier that needs to be given the values I mentioned above):
You'll have to reverse the first and second item (which you do from the pull down on the first item), change the Label.trailing to Label.Center X, and uncheck the "relative to margin" box, then correct the constant and multiplier values.
This approach will only work if the segmented control stretches all the way across the screen with no padding to the edges. If you want padding to the edges, then you need to use a completely different approach. You would need to create 5 UIViews below your segmented control -- align the left edge of the left-most one to the left edge of the segmented control. Align the right edge of the right-most one to the right edge of the segmented control. Give the 5 views equal width, and 0 length horizontal spacing constraint from each to its neighbor. This will give you 5 views that mimic the segmented control in width, with each view being the same width as one of the segments (assuming all the segments are the same width -- if that's not the case, you're screwed). Then you only need to add your labels as subviews of these 5 views, and give them centerX and centerY constraints.
I am having troubles aligning multiple images by using auto-layout in xcode.
I tried different settings, but nothing seems to work yet (refer to attached photos).
It would be great to hear some opinions from you guys, either in code or storyboard.
I want the image to be aligned equally in different screen sizes.
Too much space
Last image scaled too much
When Equally width is set
Constraints Setting
You need extra views to achieve this
In the sample picture the red rectangles they are all invisible UIView with constraints:
fixed length leading space to the view on the left(or the superview)
fixed length trailing space to the view on the right(or the superview)
fixed length height
This way it's the invisible views who have different width in different screen size while the size of images between them is fixed.
For left most item you should specify leading space to superview, for right most specify trailing space to superview. For all inner gaps between views specify horizontal spacing and for each neighbor view specify equal width constraint. Additionally I recommend for you to specify Align center Y for all views and set the y position constraint only for one of them
On the left is the normal state of the layout. On the right is the expanded state of the layout.
My problem is that I can't figure out how to keep the pink boxes centered within their cells, and the green lines connected between the pink boxes as the layout grows in any direction.
The AutoSizing.xib with just these two views can be found here: https://dl.dropboxusercontent.com/u/6979623/AutoSizing.xib
There are two approaches to keeping the pink boxes centered within the four quadrants of the super view:
You can add four invisible views that even split up the four quadrants of this main view (using constraints to pin them to their respective corners and another set of constraints to make them equal widths and heights). If I were going to represent that in VFL (just because it's a concise way of representing all of those constraints), it might be something like:
H:|[quadrant1][quadrant2(==quadrant1)]|
H:|[quadrant3(==quadrant1)][quadrant4(==quadrant1)]|
V:|[quadrant1][quadrant3(==quadrant1)]|
V:|[quadrant2(==quadrant1)][quadrant4(==quadrant1)]|
You can then center the pink views in the center of each of those four quadrant views.
You can add center constraints that employ multipliers to offset these pink squares within their shared superview. Interface Builder has only recently gotten multiplier support and it's not super solid, in my opinion, so when I want to use multipliers, I often fall back to adding those programmatically.
Once you have the pink boxes laid out correctly, then the green lines between them are simply fixed spacing leading/trailing or top/bottom for horizontal or vertical lines, respectively. Combine that with fixed width and center alignment and you're done. Bottom line, take care of the placement of the pink boxes, as discussed above, and then the creation of the green lines becomes pretty easy.
Imagine you have four or so views, all width 100, different heights. You have a wrapper view W which holds them all.
A |
B | W
C |
D |
the heights of the small views can change. At that time you want them all to move, float, appropriately, and resize W.
Now, I was just about to write a few lines of code to do this.
So .. (1) you'd have W find all the subviews and list them in order from top to bottom. Then (2) each time there is a change, you'd (3) reposition each of ABCD. the position of each one is the sum of the heights of the items above it, and (4) resize W to the sum of all heights.
Now that's all fine but -- idiots reinvent the wheel!
Am I missing something obvious in iOS? is there already a package everyone uses to do this all the time? Or something built in? What's the situation?
(Note that of course frustratingly, for our Android friends this is built in! And of course any web-html system does this automatically.)
What's the right engineering solution for iOS views here? For the record this is iOS7+ only, no old-fashioned stuffs need be covered, if it makes a difference. Cheers
(1) you'd have W find all the subviews and list them in order from top
to bottom. Then (2) each time there is a change, you'd (3) reposition
each of ABCD. the position of each one is the sum of the heights of
the items above it, and (4) resize W to the sum of all heights.
You can use constraints in Interface Builder for that whole process, no code required. Do this:
set the width of subview A to 100
constrain B, C, and D to match A's width
add vertical spacing constraints between A and B, B and C, and C and D to maintain their relative position
add a vertical spacing constraint between W (the superview, shown in gray) and A
add a vertical spacing constraint between W and D
add leading and trailing space constraints between W and view A
You'll end up with something that looks like this:
The constraints editor in Xcode isn't completely intuitive, but it is easy to use once you understand what you can and can't do with constraints in IB and when you need to use code to set up the constraints.
Suppose I have a view that contains two columns of objects. The first column contains labels, and the second column contains, say, sliders. I want the sliders all to align left with each other. I want the labels all to align left with each other. The trick is, how can I set the spacing between the labels and sliders so that the default spacing is used between the left sliders and the longest label, thus:
label 1 slider 1
label 2 slider 2
longer label 3 slider 3
very long label 4[]slider 4
label 5 slider 5
I've placed square brackets, [], where the default spacing should be. Is it possible to add this sort of constraint in the storyboard (iOS 7)? If so, how? The trick is that I don't know which label is the longest, especially with localization.
Ideally, I could specify a bounding box around the labels and align the sliders with the right side of the bounding box.
Yes, you can do this in IB. All the labels should have their left edges aligned, and one of them should have a fixed space to the left edge of their superview (all the elements should be enclosed in a UIView). Similarly, the sliders would have their right edges aligned and one of them would have a fixed space to the right edge of the box. Give one of the labels a horizontal spacing constraint to a slider -- make that a short one, say ==8 with a priority of 900 (that's the important thing). Now, give all the labels a >= constraint with whatever value you want for the minimum spacing (and leave the priority at 1000).