Search code examples
xcodeautolayoutconstraintsinterface-builderuistackview

How to get rid of unwanted constraint added by UIStackView?


I have a segmented control within a (vertical) stack view and want its leading and trailing edges to have some distance from the left and right boundaries of the stack view.

I have tried defining a width constraint to do this and have tried trailing and leading space constraints, but at runtime they get broken bc the system is not able to "simultaneously satisfy constraints". It is pretty clear from the console what the conflicting constraints are, but I did not add (see pic below) the ones that bind the segmented control to the left and right edge of its UIStackView container, therefore I do not know how to get rid of them. The system breaks the constraint that I want to keep.

I should be clear that I don't necessarily require a width constraint for the UISegmentedControl -- trailing and leading space constraints would serve also. To be utterly clear I need to be able to control the width of the segmented control.

Notice $WIDTH-SEGCTRL in the console output below. It is from the identifier I defined in the constraint in Interface Builder.

2018-11-29 10:43:56.323503-0600 [21479:18697482] [LayoutConstraints] Unable to simultaneously satisfy constraints.
    Probably at least one of the constraints in the following list is one you don't want. 
    Try this: 
        (1) look at each constraint and try to figure out which you don't expect; 
        (2) find the code that added the unwanted constraint or constraints and fix it. 
(
    "<NSLayoutConstraint:0x604000291440 H:[UIStackView:0x7f96373120d0]-(0)-|   (active, names: '|':SectionHeaderView:0x7f9637311e20 )>",
    "<NSLayoutConstraint:0x6040002985b0 H:|-(0)-[UIStackView:0x7f96373120d0]   (active, names: '|':SectionHeaderView:0x7f9637311e20 )>",
    "<NSLayoutConstraint:0x6000004913f0 '$WIDTH-SEGCTRL' UISegmentedControl:0x7f9637312d90.width == 280   (active)>",
    "<NSLayoutConstraint:0x60400029af90 '_UITemporaryLayoutWidth' SectionHeaderView:0x7f9637311e20.width == 320   (active)>",
    "<NSLayoutConstraint:0x604000486720 'UISV-alignment' UIStackView:0x7f96373122d0.leading == UISegmentedControl:0x7f9637312d90.leading   (active)>",
    "<NSLayoutConstraint:0x604000486770 'UISV-alignment' UIStackView:0x7f96373122d0.trailing == UISegmentedControl:0x7f9637312d90.trailing   (active)>",
    "<NSLayoutConstraint:0x604000486680 'UISV-canvas-connection' UIStackView:0x7f96373120d0.leading == UIStackView:0x7f96373122d0.leading   (active)>",
    "<NSLayoutConstraint:0x6040004866d0 'UISV-canvas-connection' H:[UIStackView:0x7f96373122d0]-(0)-|   (active, names: '|':UIStackView:0x7f96373120d0 )>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x6000004913f0 '$WIDTH-SEGCTRL' UISegmentedControl:0x7f9637312d90.width == 280   (active)>

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.

Below are pics of before and after I add the width constraint that generates the problem. You can see that Xcode regards the 280 width constraint as something it is unable to carry out. It regards the segmented control as bound to the edges, but I cannot figure out why.

Before: enter image description here

After: enter image description here


Solution

  • To do this with your stack view layout...

    For the Vertical Stack View, set Alignment: Center

    For the Horizontal Stack View, set Width equal to Vertical Stack View Width

    For the Segmented Control, set Width equal to Vertical Stack View Width with a constant of -40, which will leave 20-pts padding on each side. Adjust the constant to your liking, or set the Multiplier to 0.9 to make the segmented control 90% of the width.

    enter image description here