简体   繁体   English

AutoLayout可保持视图大小成比例

[英]AutoLayout to keep view sizes proportional

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) 我的xib中有2个视图需要保持20个像素的边缘(两侧和顶部)
  • The 2 views that need to resize aren't the same size 需要调整大小的2个视图的大小不同
  • They have to be 20 pixels apart 它们必须相隔20个像素
  • 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. 我阅读了一个关于这样做的教程并且它可以工作,但问题是它需要两个视图具有相同的宽度和引脚Widths equally ,这是我不想要的。

Here's what I tried: 这是我试过的:

  • Add leading space constraint to left view to be 20 pixels 将前导空间约束添加到左视图为20像素
  • Add top space constraint to left view to be 20 pixels 将顶部空间约束添加到左视图为20像素
  • Add top space constraint to right view to be 20 pixels 将顶部空间约束添加到右视图为20像素
  • Add tailing space constraint to right view to be 20 pixels 将尾部空间约束添加到右视图为20像素
  • Add horizontal spacing constraint to both views to be 20 pixels 将水平间距约束添加到两个视图为20像素

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. 我遇到的问题是左视图没有调整大小,右视图填充空间以保持20像素的水平空间。

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布局约束定义

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)]>

I'm probably late in coming up with a solution but this can actually be made very easily in IB . 我可能会提出一个解决方案,但实际上这可以在IB中 轻松实现。

First, add a UIView and pin in to all four edges of the superview. 首先,将UIView添加到superview的所有四个边缘。

Then, Add your first subview and position it accordingly (ig : x = 0, y = 0, height = fixed height, width = The width you would like relative to the UIView we pinned to all four edges). 然后,添加您的第一个子视图并相应地定位它(ig:x = 0,y = 0,高度=固定高度,宽度=您希望相对于我们固定到所有四个边缘的UIView的宽度)。

Select both the UIView and the first subview and add an Equal Widths constraint. 选择UIView第一个子视图并添加Equal Widths约束。 Of course, this will show you an error in positioning in the autolayout, but that's OK because this is not (yet) what you want. 当然,这将显示自动布局中的定位错误,但这没关系,因为这不是(还)你想要的。

Now comes the trick : select the Equal Widths constraint and edit the Multiplier to be the ratio you want (eg : 1:4 if you want the first subview to be 1/4 of the UIView). 现在就是诀窍:选择Equal Widths约束并将Multiplier编辑为您想要的比例(例如:如果您希望第一个子视图是UIView的1/4,则为1:4)。 Repeat steps for the second subview and Tadaaaaaa ! 重复第二个子视图和Tadaaaaaa的步骤!

在此输入图像描述

I'm new to autolayout but came across your question and thought it would be a good challenge. 我是autolayout的新手,但遇到了你的问题并认为这将是一个很好的挑战。 (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. 我通过首先在没有宽度约束的NIB中添加两个视图来实现这一点。 These are the constraints for the first (left) view: 这些是第一个(左)视图的约束:

在此输入图像描述

These are the constraints I had for the second (right) view: 这些是我对第二个(右)视图的限制:

在此输入图像描述

This leaves an extra constraint you don't want on the second view - leading space between superview and the second view as shown below: 这会在第二个视图中留下您不想要的额外约束 - 超视图和第二个视图之间的前导空间,如下所示:

在此输入图像描述

You can't remove that constraint in IB as it would leave an ambiguous layout (as we don't have widths on the subviews). 您无法在IB中删除该约束,因为它会留下不明确的布局(因为我们在子视图上没有宽度)。 However you can remove it in code. 但是,您可以在代码中删除它。 Firstly, set up an outlet for it and connect it in IB: 首先,为它设置一个插座并在IB中连接它:

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

Then, in your view controller's viewDidLoad , you can remove it using: 然后,在视图控制器的viewDidLoad ,您可以使用以下命令将其删除:

[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: 另请注意,您必须将常量参数设置为等于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];

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 . 这可以通过添加一个虚拟视图( dummyView )来解决,其约束设置为固定宽度,高度并与Superview的centerX对齐。然后将左视图和右视图水平间距约束添加到dummyView

在此输入图像描述在此输入图像描述

Just select the aspect ratio : 只需选择宽高比:

在此输入图像描述

As others have mentioned, the key is setting a multiplier on the "Pin Widths Equally" constraint so that the views widths end up being a multiple of each other. 正如其他人所提到的,关键是在“Pin Widths Equally”约束上设置一个乘数,以便视图宽度最终成为彼此的倍数。 XCode 5.1 should add the ability to set this in Interface Builder, but until then you've got another option besides setting it in code. XCode 5.1应该添加在Interface Builder中设置它的能力,但除此之外,除了在代码中设置它之外,你还有另一种选择。 If you create the "Pin Widths Equally" constraint, then go to the Identity Inspector in the Utilities Panel on the right, then look for "User Defined Runtime Attributes". 如果创建“Pin Widths Equally”约束,则转到右侧Utilities面板中的Identity Inspector,然后查找“User Defined Runtime Attributes”。 Add a new attribute with key path "multiplier", type "number", and value equal to your desired ratio. 使用键路径“multiplier”添加一个新属性,键入“number”,并将值等于所需的比率。

乘数设置为运行时属性,如上所述。

This won't be reflected in Interface Builder, but will apply when your view is used. 这不会反映在Interface Builder中,但会在使用您的视图时应用。

  1. Remove the two width constraints in code, or lessen their priorities in IB, otherwise you are over-constrained. 删除代码中的两个宽度约束,或者减少IB中的优先级,否则会过度约束。
  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]; 

In Interface Builder drag the view with right button (just a bit to display black popup). 在Interface Builder中,使用右键拖动视图(只需稍微显示黑色弹出窗口)。
In popup menu select Aspect Ratio . 在弹出菜单中选择“ Aspect Ratio

现在可以在XCode 6中使用宽高比属性

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. 看起来从您发布您设置一些限制是明确的屏幕抓取-例如,你的左边绿色视图有一个约束,上面写着“宽度(90)”,这意味着宽度必须等于90完全指出。

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). 这可以通过多种方式修复 - 您可以删除视图上的显式宽度约束,也可以更改其优先级(默认约束是'required',但您可以将它们更改为可选)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM