Search code examples
iosinterface-builderuisegmentedcontrolnslayoutconstraint

UISegmentedControl Not Honoring NSConstraint for Width


I have setup a screen with multiple UISegmentedControl. Using Auto-Layout/NSLayoutConstraints, I have set the first UISegmentControl to have width of "0.9 the width of the superview".

I then set the 2nd and 3rd UISegmentedControl to have width equal to the 1st UISegmentedControl.

In the end, I am getting UISegmentedControls that are not the same width. Depending on the number of segments, the UISegmentedControl might have a white space on the right end. With the white space, the entire area is equal to the desired with width - but if I set the background to be transparent, the UISegmentedControl is not wide enough, because the segments are not being drawn wide enough.

I have circled the white gap in the attached image. space on right end of 2nd UISegmentedControl

Any advice would be appreciated.


Solution

  • It looks to me like you've run into a bug with UISegmentedControl. I found that it is possible to reproduce this even without NSLayoutConstraints, although much less likely!

    In your case, your proportional constraint of 0.9 would result in a fractional width on several devices. It appears that the auto-calculated width of the segments does not like this, which is why the gap appears.

    I set up a similar view, with three segment controls set to 0.9 of the super view's width.

    Three UISegmentControls, with gap showing on right edge

    Now you can see they have the same frames (the white background), but the middle control doesn't fit the whole width.

    I was able to correct the problem by overriding viewDidLayoutSubviews in my viewController and adjusting the frame of my segmentedControl if the width is fractional.

    - (void)viewDidLayoutSubviews
    {
        for (UIView *subview in self.view.subviews) {
            if ([subview isKindOfClass:[UISegmentedControl class]]) {
                CGRect frame = subview.frame;
                CGFloat frameWidth = CGRectGetWidth(frame);
                CGFloat roundedWidth = roundf(frameWidth);
                if (frameWidth != roundedWidth) {
                    frame.size.width = roundedWidth;
                    subview.frame = frame;
                }
            }
        }
    }
    

    Which produces this result

    enter image description here