AutoLayout to keep view sizes proportional

2019-01-13 12:16发布

I'm trying to achieve the following:

  • I have 2 views in my xib that need to stay 20 pixels off the edge (both sides and top)
  • The 2 views that need to resize aren't the same size
  • They have to be 20 pixels apart
  • Their width needs to stay relative to the width of the parent view

I read a tutorial about doing just that and it works but the problem with it is that it requires both views to have the same width and pin Widths equally, which I don't want.

Here's what I tried:

  • Add leading space constraint to left view to be 20 pixels
  • Add top space constraint to left view to be 20 pixels
  • Add top space constraint to right view to be 20 pixels
  • Add tailing space constraint to right view to be 20 pixels
  • Add horizontal spacing constraint to both views to be 20 pixels

The problem I'm running into is that the left view doesn't resize and the right view fills out the space to keep the 20 pixels horizontal space.

Is there a way I can get both views to resize proportionally to the space they should be filling?

Here are the screenshots of my layout and constraints:

xib LayoutConstraints definitions

Thanks!

EDIT

I get the following warning when I try to rotate my device:

2012-10-11 08:59:00.435 AutolayoutTest[35672:c07] 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. (Note:  
    If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) 
(
    "<NSLayoutConstraint:0x8a6b2b0 H:[UIView:0x8a6b1d0(170)]>",
    "<NSLayoutConstraint:0x8a68ad0 H:[UIView:0x8a69430(90)]>",
    "<NSLayoutConstraint:0x8a6ba40 H:[UIView:0x8a69430]-(20)-[UIView:0x8a6b1d0]>",
    "<NSLayoutConstraint:0x8a6ba00 H:[UIView:0x8a6b1d0]-(20)-|   (Names: '|':UIView:0x8a6b7e0 )>",
    "<NSLayoutConstraint:0x8a6b940 H:|-(20)-[UIView:0x8a69430]   (Names: '|':UIView:0x8a6b7e0 )>",
    "<NSAutoresizingMaskLayoutConstraint:0x7199aa0 h=--& v=--& V:[UIView:0x8a6b7e0(568)]>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x8a6b2b0 H:[UIView:0x8a6b1d0(170)]>

9条回答
仙女界的扛把子
2楼-- · 2019-01-13 12:43

This can be resolved by adding one more dummy view(dummyView) with its constraints set to Fixed width, height and aligned to centerX of Superview.Then add left view and right view Horizontal spacing constraint to dummyView.

enter image description here enter image description here

查看更多
够拽才男人
3楼-- · 2019-01-13 12:44
  1. Remove the two width constraints in code, or lessen their priorities in IB, otherwise you are over-constrained.
  2. Add a constraint to describe the width ratio between the green view and blue view, in code:

    // Assuming the ratio you want is green_view_width : blue_view_width = 1 : 2
    NSLayoutConstraint *c = [NSLayoutConstraint constraintWithItem:greenView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:blueView attribute:NSLayoutAttributeWidth multiplier:0.5f constant:0.f];
    [commonSuperview addConstraint:c];
    
查看更多
做个烂人
4楼-- · 2019-01-13 12:45

I'm new to autolayout but came across your question and thought it would be a good challenge. (That's my caveat in case this isn't the ideal solution!)

You'll need to add the width constraints in code. I achieved this by firstly adding the two views in the NIB without width constraints. These are the constraints for the first (left) view:

enter image description here

These are the constraints I had for the second (right) view:

enter image description here

This leaves an extra constraint you don't want on the second view - leading space between superview and the second view as shown below:

enter image description here

You can't remove that constraint in IB as it would leave an ambiguous layout (as we don't have widths on the subviews). However you can remove it in code. Firstly, set up an outlet for it and connect it in IB:

@property (nonatomic, strong) IBOutlet NSLayoutConstraint *view2superviewLeadingConstraint;

Then, in your view controller's viewDidLoad, you can remove it using:

[self.view removeConstraint:self.view2superviewLeadingConstraint];

Finally, add the width constraints. The key here is the multiplier parameter to dicate what percentage you want the widths to be based on the superview width. Also note that you have to set the constant parameters to equal the leading/trailing totals set up in IB:

NSLayoutConstraint *constraint1 = [NSLayoutConstraint constraintWithItem:self.view1 attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeWidth multiplier:0.3 constant:-20];
[self.view addConstraint:constraint1];

NSLayoutConstraint *constraint2 = [NSLayoutConstraint constraintWithItem:self.view2 attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeWidth multiplier:0.7 constant:-40];
[self.view addConstraint:constraint2];
查看更多
Fickle 薄情
5楼-- · 2019-01-13 12:46

Just select the aspect ratio :

enter image description here

查看更多
劫难
6楼-- · 2019-01-13 12:51

It's now possible in XCode 6 with the aspect ratio property

查看更多
再贱就再见
7楼-- · 2019-01-13 12:53

I'm not sure how familiar you are with auto-layout, so apologies if this is stuff you already know:

When using auto-layout it's possible to assign several constraints to the same property. Under certain circumstances these constraints can contradict each other. This is what's causing the warning you're seeing.

It looks from the screen-grab you posted that you've set several constraints to be explicit - for example, your green view on the left has a constraint that says "Width (90)", which means the width must be equal to 90 points exactly.

It's unclear from the screenshot alone what your other constraints are mapped to, but what's probably happening here is these explicit constraints are causing problems - you have autoresizing constraints that say the views should expand or contract to fit their available area, but those same views have constraints that require them to be an exact width.

This can be fixed in a number of ways - you can either remove those explicit width constraints on your views, or you can change their priority (by default constraints are 'required', but you can change them to be optional).

查看更多
登录 后发表回答