Search code examples
iosautolayout

Resolve ambiguity with content hugging priority


Important: this question is not about adding/removing/modifying constraints!

I need help with understanding why the following layout is ambiguous:

UIView (rootView)
|   UIView (topView)
|   UIView (bottomView)

Constraints setup: V:|[topView][bottomView]|, and content hugging priority of bottomView is higher than the content hugging of the topView.

I would understand it if both views would have the same content hugging priority, but since the value is higher on bottomView I expect that it should resist more growing larger.

Below I paste the code you can use in a "Single View App" Xcode project template:

//
//  ViewController.m
//

#import "ViewController.h"

@interface ViewController ()
@property (strong, nonatomic) UIView* rootView;
@property (strong, nonatomic) UIView* topView;
@property (strong, nonatomic) UIView* bottomView;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    [self setupViewHierarchy];
    [self setupIssueIrrelevantConstraints];
    [self setupIssueRelevantConstraints];
    [self bumpVerticalContentHuggingPriorityOfView:self.bottomView];
}

- (void)setupViewHierarchy {
    self.view.backgroundColor = [UIColor lightGrayColor];

    self.rootView = [UIView new];
    self.rootView.translatesAutoresizingMaskIntoConstraints = NO;
    [self.view addSubview:self.rootView];

    self.topView = [UIView new];
    self.topView.translatesAutoresizingMaskIntoConstraints = NO;
    self.topView.backgroundColor = [UIColor greenColor];
    [self.rootView addSubview:self.topView];

    self.bottomView = [UIView new];
    self.bottomView.translatesAutoresizingMaskIntoConstraints = NO;
    self.bottomView.backgroundColor = [UIColor blueColor];
    [self.rootView addSubview:self.bottomView];
}

- (void)setupIssueIrrelevantConstraints {
    [self.rootView.widthAnchor constraintEqualToConstant:200.0].active = YES;
    [self.rootView.heightAnchor constraintEqualToConstant:200.0].active = YES;
    [self.rootView.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor].active = YES;
    [self.rootView.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor].active = YES;

    [self.topView.leftAnchor constraintEqualToAnchor:self.rootView.leftAnchor].active = YES;
    [self.topView.rightAnchor constraintEqualToAnchor:self.rootView.rightAnchor].active = YES;

    [self.bottomView.leftAnchor constraintEqualToAnchor:self.rootView.leftAnchor].active = YES;
    [self.bottomView.rightAnchor constraintEqualToAnchor:self.rootView.rightAnchor].active = YES;
}

- (void)setupIssueRelevantConstraints {
    [self.topView.topAnchor constraintEqualToAnchor:self.rootView.topAnchor].active = YES;
    [self.bottomView.bottomAnchor constraintEqualToAnchor:self.rootView.bottomAnchor].active = YES;
    [self.topView.bottomAnchor constraintEqualToAnchor:self.bottomView.topAnchor].active = YES;
}

- (void)bumpVerticalContentHuggingPriorityOfView:(UIView*)view {
    UILayoutPriority contentHuggingPriority = [view contentHuggingPriorityForAxis:UILayoutConstraintAxisVertical];
    contentHuggingPriority++;
    [view setContentHuggingPriority:contentHuggingPriority
                            forAxis:UILayoutConstraintAxisVertical];
}

@end

I know what ambiguous layout is, and no more constraints are required to resolve that layout. I expect that bottomView height will be equal to 0 because since its content hugging priority is larger it should resist more growing than topView.


Solution

  • The trouble is that you have a misconception of what content hugging is. It is about content.

    Content hugging is relevant only when a view has an intrinsic content size, as does a label or a button.

    https://developer.apple.com/documentation/uikit/uiview/1622600-intrinsiccontentsize

    Content hugging is the priority with which, in the face of other constraints, a view should obey the dictates of its intrinsic content size. That’s all it is.

    But your views do not have any intrinsic content size; there is no content to hug. Therefore your content hugging settings are meaningless and ignored.