为啥 Interface Builder 不能为约束设置负倍数,即使 [NSLayoutConstraint constraintWithItem:] 可以?

Posted

技术标签:

【中文标题】为啥 Interface Builder 不能为约束设置负倍数,即使 [NSLayoutConstraint constraintWithItem:] 可以?【英文标题】:Why can't Interface Builder set a negative multiple for a constraint, even though [NSLayoutConstraint constraintWithItem:] can?为什么 Interface Builder 不能为约束设置负倍数,即使 [NSLayoutConstraint constraintWithItem:] 可以? 【发布时间】:2017-01-08 05:22:40 【问题描述】:

我有一个 ios 9 和 10 应用程序,它在窗口底部有一个小“托盘”UIView,它可以滑入和滑出以显示(或隐藏)某些控件。默认情况下,托盘完全显示(“滑出”),因此用户可以看到所有内容。最右边有一个按钮,他们可以点击该按钮使托盘“滑入”到左侧,这样托盘大部分都被隐藏了,因为它现在在左侧屏幕外。 (最右边的 20 个点是用户可以点击以滑入/滑出的“拇指”,因此拇指是托盘滑入时唯一保持可见的部分。)

我想这样做的方法是通过 Interface Builder 定义两个不同的约束,我只是简单地切换它们,以便一次只有一个处于活动状态。例如,这两个约束可能是:

trayOutConstraint:

trayView.leading = (superview.leading * 1) + 0 // 结果 == 0

trayInConstraint:

trayView.leading = (superview.trailing * -1) + 20 // 结果 == -300(例如)

事实证明,我可以通过编程方式为 trayInConstraint 创建约束,如下所示(编辑:展开以显示我如何禁用情节提要的默认约束并添加我的新约束):

// Disable the default constraint (in the storyboard)
[[self trayTripOutLeadingConstraint] setActive:NO];

// Create the new constraint (add to an array by itself)
NSLayoutConstraint *newConstraint = [NSLayoutConstraint constraintWithItem:(id)trayView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:(id)[trayView superview] attribute:NSLayoutAttributeTrailing multiplier:-1 constant:20];
NSArray *newTrayConstraintsArray = [[NSArray alloc] initWithObjects:newConstraint, nil];

// Remove any existing constraints array and use the new one    
[[self view] removeConstraints:[self tripTrayConstraints]];
[self setTripTrayConstraints:newTrayConstraintsArray];
[[self view] addConstraints:newTrayConstraintsArray];

但如果我尝试在 Interface Builder 中创建它,我无法将乘数设置为 1.0 以外的任何值。 (键入任何其他值只会强制它重置为“1”。)

我在 Apple 文档中看到 https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/AutolayoutPG/AnatomyofaConstraint.html

您不能将非恒等乘数(1.0 以外的值)与 位置属性。

但是为什么我可以用代码而不是 IB 来创建呢?

(除了可能对其他人有用的无关之外:我还想创建一个约束,其中倍数为 0,但无法以编程方式或在 IB 中执行此操作。我发现我可以解决无法使用“0.0”的问题" 作为乘数,而是使用非常小的值,例如 0.000001。)

【问题讨论】:

你是如何分配新约束的,你能在这里告诉我吗? 我已经编辑了我的问题以包含创建和分配新约束的代码。但这不是我的问题。我的问题不是如何创建创建所需约束的代码。我已经知道了,如上面的代码所示。相反,我的问题是:为什么我不能为 Interface Builder 中的“乘数”分配一个值“-1”? 【参考方案1】:

选择"Reverse First And Second Item" 并重新输入乘数的绝对值 => 这样(通过切换第一项和第二项)乘数的行为就像是负数一样。

第一项:View.Leading 第二项:Superview.Trailing

第一项:Superview.Trailing 第二项:View.Leading

【讨论】:

感谢您的回复,但我认为这是不对的,因为乘法不会根据参数的顺序给出不同的符号结果。例如:(320 * -1) == (-1 * 320)。 这与符号无关,因为您必须使用正乘数。这是关于应用值的位置。向右走 -320 点与向左走 320 点相同。因为你不能向右走 -320 点 - 你必须改变方向 => “反转第一个和第二个项目”。 感谢 cmets,他们帮助我找到了不同的解决方案。当托盘滑入时,我一直试图像这样限制前导:“trayView.leading = (superview.trailing * -1) + 20” 你的评论让我意识到我可以通过控制托盘的另一侧。即,我设置了尾随而不是前导!所以解决方案变成了“trayView.trailing = (superview.leading * 1) + 20”再次感谢!【参考方案2】:

您可以为leading, trailing, top and bottom constraints simply 分配负值。但是您不能从代码或界面生成器中为任何乘数分配负值。如果您在代码中添加任何负值作为乘数,编译器会将其视为 +1,您可能会得到意想不到的结果。 (在您的情况下,您可能会意外得到预期的结果)

【讨论】:

“您不能从代码或界面生成器中为任何乘数分配负值...”是什么让您这么说? Apple 文档中是否有任何指定?

以上是关于为啥 Interface Builder 不能为约束设置负倍数,即使 [NSLayoutConstraint constraintWithItem:] 可以?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 Interface Builder 不会改变我的 ViewController 类型?

Interface Builder:为啥我的 UIView 是透明的?

为啥其他东西通过 Interface Builder xib 调用连接到 UIBarButtonItem 的方法?

为啥我的自定义类没有出现在 Interface Builder 的下拉列表中?

为啥在 Interface Builder 中更改字体大小会阻止 UILabel 调整大小以适应内容?

为啥新类不会出现在 Interface Builder 的 Identity Inspector/Custom Class 中?