0

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?

Community
  • 1
  • 1
CommaToast
  • 11,370
  • 7
  • 54
  • 69
  • Are all the segments of your segmented controller the same size? BTW, nothing is specified in pixels, it's specified in points. Also, there's nothing hacky about using spacer views, it is the easiest way to space views out evenly, but I don't think you need to do that. Why can't you center align your text, and give the labels flexible width and all the same size? – rdelmar Apr 14 '15 at 21:36
  • Point taken regarding "pixels" vs. "points" (pun intended). All the segments of the segmented controller are the same width. I must use a fixed width for the individual UILabels so they line up with certain graphics that are in the background of their view. I can't give the text center alignment because of decimal point alignment issues that happen inside a stack of UI Labels beneath each segment of the UISegmentedControl and also because of the graphics alignment issue. I could use empty spacer views but that seems very hackish and dumb... surely there are flexible spaces? – CommaToast Apr 14 '15 at 22:37
  • No, there are no flexible spaces (that would be nice). It's hard to understand, without more detail, exactly what in your labels you're trying to align with the titles of the segmented control. Unless you center align them , or they all have the same length text, I don't think they will look aligned. An image of what you're trying to do would be helpful. – rdelmar Apr 15 '15 at 00:17
  • Just think of it in terms of the bounding box of the UILabels. Each left and right side of the bounding box of each UILabel should be equidistant to the left and right border of the segment above it in the UISegmentedControl. Don't worry about the actual text inside the UILabel. Just the bounding box! – CommaToast Apr 15 '15 at 00:21

1 Answers1

0

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):

enter image description here

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.

rdelmar
  • 103,982
  • 12
  • 207
  • 218