ios 了解自动布局中的乘数以使用相对定位

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26964139/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 03:39:22  来源:igfitidea点击:

Understanding multiplier in auto layout to use relative positioning

iosautolayoutnslayoutconstraint

提问by Jordan H

I am trying to understand how one can utilize Auto Layout to position items relative to other views percentage-wise.

我试图了解如何利用自动布局来相对于其他视图按百分比定位项目。

For example, I recently learned that you can specify a view's bottom should lie 4% higher than its superview's bottom by using this:

例如,我最近了解到您可以使用以下命令指定视图的底部应该比其父视图的底部高 4%:

self.view.addConstraint(NSLayoutConstraint(item: label, attribute: .Bottom, relatedBy: .Equal, toItem: self.view, attribute: .Bottom, multiplier: 0.96, constant: 0))

This makes sense to me because a multiplier of 1 would align it right at the view's bottom, so you can decrease that amount by 4 percent by changing the multiplier to 0.96.

这对我来说很有意义,因为乘数为 1 会使其与视图底部对齐,因此您可以通过将乘数更改为 0.96 来减少 4% 的数量。

But how can you do the same in the other direction? You want to specify a label's top should begin 4% down from the superview's top. If you use that same line but change the attributes to .Top, that means it would be 4% higher than the superview's top (but it actually doesn't move it off screen). You can't have a negative multiplier I don't think, and I don't believe a value greater than 1 does anything when constant is 0. So how do you get that set up?

但是你怎么能在另一个方向做同样的事情呢?你想指定一个标签的顶部应该从父视图顶部向下 4% 开始。如果您使用同一行但将属性更改为.Top,则意味着它将比超级视图的顶部高 4%(但实际上并没有将其移出屏幕)。我不认为你不能有负乘数,而且我不相信当常数为 0 时,大于 1 的值不会做任何事情。那么你如何设置呢?

I have the same question for implementing leading and trailing. Trailing is easy. If you want it 10% from the right:

我对实施领先和尾随有同样的问题。拖尾很容易。如果你想要它从右边 10%:

self.view.addConstraint(NSLayoutConstraint(item: label, attribute: .Trailing, relatedBy: .Equal, toItem: self.view, attribute: .Trailing, multiplier: 0.9, constant: 0))

It makes sense because you dial it back 0.1 or 10% instead of aligning fully at 1.0. But how do you do the same for leading? I thought you might be able to set the label's leading relative to the view's trailing, then set the multiplier to 0.1. In my mind that would mean the label would start at the very far right but then be dialed back 90%, therefore obtaining the desired 10% from the left. But that's not the case, I'm not sure why.

这是有道理的,因为您将其拨回 0.1 或 10%,而不是完全对齐 1.0。但是你如何为领导做同样的事情?我认为您可以设置标签相对于视图尾随的前导,然后将乘数设置为 0.1。在我看来,这意味着标签将从最右边开始,然后再拨回 90%,因此从左边获得所需的 10%。但事实并非如此,我不知道为什么。

Can you explain how this is works, how to properly use multiplier to obtain these relative layouts?

你能解释一下这是如何工作的,如何正确使用乘数来获得这些相对布局?

To make it easy, let's say you'd like to create a label that has top and bottom 10% of the superview's height, and trailing and leading 10% of the superview's width. On an iPhone in portrait there's going to be more padding above and below the label than there is padding to the left and right of it, like so (yes it's drawn to scale):
enter image description here

But let's say on the iPad it's going to be shown in a view that's a perfect square. Therefore the padding will be the same amount all around, like so:
enter image description here

The question is how do you define such constraints to be dynamic in value, as opposed to setting a fixed value for a constant. I already know how to do bottom and trailing, but top and leading has me stumped. I'm hoping to understand how to use multiplier to do more advanced layouts, for example, specifying a label's top should lie 10% beneath another label's bottom, as opposed to setting it to a fixed constant.

为简单起见,假设您想创建一个标签,其顶部和底部为父视图高度的 10%,尾随和前导为父视图宽度的 10%。在纵向的 iPhone 上,标签上方和下方的填充会比标签左右的填充更多,就像这样(是的,它是按比例绘制的):
在此处输入图片说明

但是让我们说在 iPad 上它会显示在一个完美的正方形的视图。因此,周围的填充量将相同,如下所示:
在此处输入图片说明

问题是您如何将此类约束定义为动态值,而不是为常量设置固定值。我已经知道如何做底部和尾随,但顶部和领先让我很难过。我希望了解如何使用乘数进行更高级的布局,例如,指定标签的顶部应位于另一个标签底部下方 10%,而不是将其设置为固定常量。

采纳答案by Archaeopterasa

There are a couple ways to do this. In the simplest case, you've already almost got it: if you want the horizontal boundaries to be at 10% and 90%, then you need to specify bothconstraints with respect to the trailing edge of the superview -- so Subview.Trailinglocks to Superview.Trailingwith a multiplier of 0.9, as you say, but then Subview.Leadingalso locks to Superview.Trailing, just with a multiplier of 0.1:

有几种方法可以做到这一点。在最简单的情况下,你已经几乎得到了它:如果你想要的水平边界是在10%和90%,那么你需要指定两个方面制约了上海华盈的后缘-这样Subview.TrailingSuperview.Trailing与的乘数0.9,如您所说,但随后Subview.Leading也锁定为Superview.Trailing,只需乘数为0.1

enter image description here

在此处输入图片说明

(and similarly for top / bottom)

(顶部/底部类似)

On the other hand, the case you mention at the end is a little more complicated: "specifying a label's top should lie 10% beneath another label's bottom." For that you probably won't be able to use fixed percentage insets like the previous case. Instead, you can create an invisible spacer view between them: add a constraint with Spacer.Height = 0.1 * Superview.Heightand then attach it between the two labels. (You can also handle the previous case with these spacer views, but for that case it isn't really necessary.)

另一方面,你在最后提到的情况稍微复杂一些:“指定一个标签的顶部应该位于另一个标签底部下方 10%。” 为此,您可能无法像前一种情况一样使用固定百分比的插图。相反,您可以在它们之间创建一个不可见的间隔视图:添加约束,Spacer.Height = 0.1 * Superview.Height然后将其附加在两个标签之间。(您也可以使用这些间隔视图处理前一种情况,但对于这种情况,它并不是真正必要的。)

回答by fujianjin6471

In my opinion, "You can't have a negative multiplier I don't think, and I don't believe a value greater than 1 does anything when constant is 0" exposed your comprehending deviation.

在我看来,“我不认为你不能有一个负乘数,而且我不相信当常数为 0 时,大于 1 的值不会做任何事情”暴露了你的理解偏差。

The rule underneath the hood is just a linear equation:

引擎盖下的规则只是一个线性方程:

FirstItem.Attribute1 = (SecondItem.Attribute2 * Multiplier) + Constant

All measured in points. As you see, multiplier(a property of NSLayoutConstraint) is not the multiplier of constant. Follow the equation, what you don't understand will be clear.

都是以点数来衡量的。如您所见,乘数(NSLayoutConstraint 的一个属性)不是常数的乘数。跟着等式,你不明白的就会清楚。

As to your specific example, @Archaeopterasa presented a great solution, another is shown below:

至于你的具体例子,@Archaeopterasa 提出了一个很好的解决方案,另一个如下所示:

Based on the fact you know how to do bottom and trailing, I suppose you've done these two. Then add another two constraints, the effect will be what you want: set label's width to 80% superview's widthset label's height to 80% superview's height

基于你知道如何做底部和追踪的事实,我想你已经完成了这两个。然后再添加两个约束,效果就是你想要的: set label's width to 80% superview's widthset label's height to 80% superview's height

At last, if you want to specify a label's top lie 10% beneath another label's bottom, it seems that you cannot implement it without writing a line of code. You have to use code to set the constant of the NSLayoutConstraint object connecting the FirstItem and the SecondItem after the superview's height is known in runtime.

最后,如果要指定一个标签的顶部位于另一个标签底部下方 10% 的位置,似乎不编写一行代码就无法实现它。在运行时已知超级视图的高度后,您必须使用代码设置连接 FirstItem 和 SecondItem 的 NSLayoutConstraint 对象的常量。

Firstly, control drag from one label to the other and choose "Vertical Spacing".(Or you can do this in other ways)

首先,控制从一个标签到另一个标签的拖动并选择“垂直间距”。(或者您可以通过其他方式执行此操作)

Secondly, a referencing outlet is needed:

其次,需要一个参考出口:

@IBOutlet weak var tenPercentOfSuperview: NSLayoutConstraint!

Then, do this in a appropriate place(for example, in viewDidLoad())

然后,在适当的地方执行此操作(例如,在 viewDidLoad() 中)

let heightOfSuperview = self.view.bounds.height
tenPercentOfSuperview.constant = heightOfSuperview * 0.1

Everything is OK now.

现在一切正常。

If you want to know more about this topic, Apple's document is recommended:https://developer.apple.com/library/ios/recipes/xcode_help-IB_auto_layout/chapters/EditingConstraintAttributesintheAttributesInspector.html

如果你想了解更多关于这个话题,推荐苹果的文档:https: //developer.apple.com/library/ios/recipes/xcode_help-IB_auto_layout/chapters/EditingConstraintAttributesintheAttributesInspector.html

回答by Fattie

Here's the

这是

INCREDIBLY SIMPLE

非常简单

way to do it.

方法来做到这一点。

Just add 'helper' or "measure' views:

只需添加“助手”或“测量”视图:

The 'calculation helper' views are yellow in the example.

示例中的“计算助手”视图是黄色的。

The general technique is so simple and obvious - it doesn't need any explantion, you can get it from the image.

通用技术就是这么简单明了——它不需要任何解释,你可以从图像中得到它。

It's one of those "elephant in the room" things they "don't teach you about" in iOS. But it is used constantly in all layouts.

这是他们在 iOS 中“不会教你”的“房间里的大象”之一。但它在所有布局中不断使用。

(Indeed, Apple should have made a special UIView subclass "measures" for exactly this purpose - and indeed, many large teams do just that, with the obvious features.)

(确实,Apple 应该为此目的制作一个特殊的 UIView 子类“措施”——事实上,许多大型团队就是这样做的,具有明显的功能。)

enter image description here

enter image description here

Notice icon #1 is centered on the right end of the "View 1/4" helper view.

注意图标 #1 位于“View 1/4”辅助视图的右端居中。

Notice icon #3 is centered on the left end of the "View 3/4" helper view.

注意图标 #3 位于“View 3/4”辅助视图左端的中央。

You're done, have a Chardonnay.

大功告成,来一杯霞多丽。

Conveniently, in the helper views, just set the multiplier to anything you want, depending on the feel wanted. It's incredibly easy to then change those in your code, use IBInspectable, animate, and so on and on...

方便的是,在助手视图中,只需将乘数设置为您想要的任何值,具体取决于所需的感觉。然后更改代码中的那些,使用 IBInspectable、animate等等非常容易......

enter image description here

enter image description here