B.S.
B.S.

Reputation: 21726

Flexible width constraint

I got stuck with resolving constraints, perhaps someone can help:

Here is the case:

I need myView to have flexible width according to superview width.

If superview has more width than 500 -> myView should have 500.

If superview has less width then 500 -> myView should take all superView width.

[NSLayoutConstraint constraintsWithVisualFormat:@"[myView(==500)]" options:0 metrics:nil views:@{
    @"myView"    : self.myView,
    @"superview" : superview
}];
// If I write myView(<=500), obviously width will be zero. 
// I can not add something like this:
// @[tableView(<=superview)]", as width can be less, can be more

So I got stuck here, any thoughts?

Thanks in advance!

Upvotes: 2

Views: 2269

Answers (3)

Dallas Johnson
Dallas Johnson

Reputation: 1536

You need more than one constraint and the use of priorities. One constraint for myView to equal the superview width as you already have and another for the myView to be NSLessThanOrEqual to 500 as suggested above. Then set the priority of the latter to be greater than the equal width constraint. I think that should be enough for the width. Maybe you'll need a 3rd constraint with lower priority to set the width of myView to 500 if it still shrinks to 0 to avoid ambiguity.

Here's an edit to my answer with some code to illustrate better:

Using visual layout as below allows for the more readable layout (once you're used to the syntax)

 NSDictionary *views = @{@"myView" : _myView, @"superView": self.view};

  [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-100-[myView(40)]" options:0
                                                                    metrics:nil
                                                                      views:views]];

  [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(3@999,>=3)-[myView(<=500)]-(3@999,>=3)-|" options:0
                             metrics:nil
                             views:views]];

If put a padding of 3 just to illustrate the shrinking to the edges.

If you wanting to center myView in the superview visual layout will be lacking and you'll need to add a long form constraint like this:

  [self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.myView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1 constant:0]];

But all of this could done in Storyboards without any code based on the same logic. If not using Storyboards I try to use the visual layout as much as possible and usually only the long form for centering views or when dynamically laying views where the structure is only known at runtime.

Upvotes: 1

Mike Sand
Mike Sand

Reputation: 2770

Visual Format Language can be kind wonky even by Auto Layout standards, especially when setting priority. The problem is actually conceptual and can be done in IB or with VFL or by the class methods. Anyway, the issue:

When you want some behavior to change in a set way when some condition is met or not met, try switching to priority instead of inequality. In this case, think of the margins: You want to the horizontal margin to be 0 when the total width is under 500, but adding space when more than 500. Constraints you will need:

  1. Required priority 1000: Set myView to less than or equal to 500.
  2. Priority 999: Set myView attached to superview with leading/trailing space=0.

If the space is less than 500, both conditions can be met. If the space is more than 500, than it will start breaking constraints, starting with the lowest priority.

Note that after breaking the margin constraints it won't know where to set the horizontal x placement of myView, so you will need another constraint. Centering in superview will conflict the least, since it can place it horizontally with or without margin constraints broken. There is a way to get it to add space on one side only, but it's a complicated dance-of-the-breaking-constriants leading to messy required programmatic intervention; I think centered-horizontally gets your intended behavior.

Upvotes: 2

Dhaivat Vyas
Dhaivat Vyas

Reputation: 2928

As per your question you need to set constraint to myView.
Here's what you need to do:

UIView *myView = [UIView new];
myView.translatesAutoresizingMaskIntoConstraints = NO;
myView.backgroundColor = [UIColor blueColor];
[self.view addSubview:myView];

NSDictionary *viewDictionary = @{@"myView":myView};

[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-50-[myView(200)]" options:0 metrics:0 views:viewDictionary]];

[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-10-[myView(<=500)]" options:0 metrics:0 views:viewDictionary]];

NSLayoutConstraint *tailing = [NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:myView attribute:NSLayoutAttributeTrailingMargin multiplier:1 constant:75];
tailing.priority = 999;
[self.view addConstraint:tailing];

Result:
enter image description here
enter image description here


Hope this might help in solving your problem.
You can visit this link for setting auto layout constraints programmatically for advance help.
ref: http://technet.weblineindia.com/mobile/ui-design-of-ios-apps-with-autolayout-using-constraints-programmatically/

ref: https://codehappily.wordpress.com/2013/10/09/ios-how-to-programmatically-add-auto-layout-constraints-for-a-view-that-will-fit-its-superview/

Upvotes: -1

Related Questions