11

I've been trying to setup a simple container view in IB using UIStackView. I want this container to center its only arranged subview and respect the intrinsic content size of the subview.

Unfortunately for all possible configuration of alignment and distribution the subview is stretched to fill the width along the axis.

This looks like a weird edge case or a bug, because once I add a second view everything behaves as expected and both subviews maintain their size defined by intrinsic content size method.

I would love to understand why UIStackView behaves like that.

Robert Wijas
  • 693
  • 7
  • 14
  • 2
    “[The stack view pins the first and last arranged view flush with its edge along the stack’s axis. For a horizontal stack, this means the first arranged view’s leading edge is pinned to the stack’s leading edge, and the last arranged view’s trailing edge is pinned to the stack’s trailing edge. For vertical stacks, the top and bottom edges are pinned, respectively.](https://developer.apple.com/library/prerelease/ios/documentation/UIKit/Reference/UIStackView_Class_Reference/)” Therefore if you put in just one subview, it will be stretched to fill the stack's axis. Is this what you're seeing? – rob mayoff Jul 19 '15 at 19:31
  • 1
    Yes. What I don't understand is why this overrides intrinsic content size even if I set the content hugging priority to high. – Robert Wijas Jul 20 '15 at 10:13

1 Answers1

15

UIStackView creates constraints with a priority of 1000 (the maximum allowed priority), which is UILayoutPriorityRequired. Auto layout is required to satisfy these constraints if possible.

Your constraint at “high” priority (UILayoutPriorityDefaultHigh == 750, I presume) conflicts with the stack view's required constraints, so auto layout will ignore your constraint.

If you set your constraint priority to 1000, then auto layout will not be able to satisfy all required constraints. It will log an error, and it will break one of the constraints. You don't get to pick which constraint it breaks.

Note that it only needs to break one of the three constraints to solve the system, and it can break any of the three conflicting constraints. However, breaking any single one of the three conflicting constraints won't leave a system that centers your view. Your view should end up either stretched, or hugging one end of the stack view, depending on which constraint auto layout breaks. And a future version of iOS might change auto layout so that a different constraint is broken and the layout changes.

It's not clear why you're trying to use a stack view to center your view. If you just have one view and you want to center it, make its parent a plain UIView instead of a UIStackView, and set up constraints to center your view in the parent view.

If you're using a stack view because sometimes you want more than one arranged subview in the stack, then you should add two hidden spacer views (one at each end of the axis) in addition to your content view(s). Create an equal-width or equal-height constraint between the spacers.

rob mayoff
  • 375,296
  • 67
  • 796
  • 848
  • Thanks! I was fooled by "Debug Hierarchy View" that showed _76_ as the constraint's priority in inspector. – Robert Wijas Jul 21 '15 at 13:16
  • Why am I trying to use stack view for centring? I was looking for something that can be set up entirely in IB. – Robert Wijas Jul 21 '15 at 13:18
  • @RobertWijas IB lets you define `.CenterX` and `.CenterY` constraints, that will center the view. Either click on the "Align" button (the second one in the bottom right corner of the IB workspace) or control-drag from the subview to its superview and you'll see the "center" options. Maybe I'm not understanding your comment. – Rob Aug 27 '15 at 16:11