自动布局(约束)在父视图中居中2个并排视图


69

我试图弄清楚如何使用自动布局(iOS6)和约束来做到这一点。

基本上,我的大视野在底部分为两个部分。在这些部分(当前为子视图)中,我具有图像视图和标签。我想用可变长的文本在两边居中。

我的头主要围绕自动布局,但是我不确定最好的方法。我倾向于认为在IB中是不可能的,但是在代码中。

继续尝试解决这个问题,但与此同时,这是我要创建的示例。

在此处输入图片说明

Answers:


66

这是你所追求的吗?

短标签 长标签

我通过viewCenteredInLeftSection在您的视图中添加一个视图(名为)来完成此操作leftSection,然后将时钟图像和标签添加为具有以下约束的子视图:

  • 使viewCenteredInLeftSection的CenterX和CenterY等于其父视图(leftSection)。
  • 使clockImage的顶部,底部和前缘等于其超级视图的(viewCenteredInLeftSection)。
  • 使label的后沿等于其超级视图的(viewCenteredInLeftSection)。
  • 使clockImage'的后沿到label'的前沿相距标准距离。

viewCenteredInLeftSection

我无法在Interface Builder中调整iOS UIView的大小,因此我以OS X为例,而我完全可以在Interface Builder中做到这一点。如果您在Interface Builder中遇到上述约束时遇到麻烦,请告诉我,我将发布将创建它们的代码。

2014-08-26编辑

Luda,这是Xcode 5的Pin和Align菜单,也可以在Xcode的菜单栏中找到:

对齐菜单 固定菜单

以下是我的示例在Interface Builder中的外观。蓝色视图是原始问题的“父视图”,即图像和标签应居中的给定视图。

我将绿色视图(我命名为viewCenteredInLeftSection)添加为“父视图”的子视图。然后,我突出显示了它,并使用“容器中的水平中心”和“容器中的垂直中心”的对齐菜单来创建约束以定义其位置。

我将时钟图像添加为的子视图viewCenteredInLeftSection,并定义了其宽度和高度。我突出显示了时钟图像和viewCenteredInLeftSection,然后使用“对齐”>“前缘”,“对齐”>“上边缘”和“对齐”>“下边缘”应用了约束。

我将标签添加为的子视图viewCenteredInLeftSection,并将其定位为时钟图像的标准Aqua空间距离。我突出显示了标签和viewCenteredInLeftSection,然后使用“对齐”>“后缘”应用了约束。

这是很多容易创建和Xcode 5的界面生成器与Xcode中4分的。

界面生成器


是的,这就是我的追求。这是一个很好的解决方案,但是通过使用代码,我能够做到这一点而无需添加额外的视图。我将在此处不久发布代码。
Bob Spryn

我发现添加一个封装的UIView比通过代码完成要容易得多。做得好!
capikaw 2014年

2
“使clockImage的顶部,底部和前沿等于其superview的边缘”是什么意思?可以在Interface Builder中完成吗?
Michael Forrest 2014年

1
@JohnSauer,您可能的意思是“对齐->尾随边缘”(不是尾随图像)
dariaa 2014年

1
这是唯一不需要编码的解决方案,即使宽度不相等的UI元素也可以使用。占位符视图是关键,而不是设置该视图的宽度,而是设置约束以使其根据其子元素调整其视图,这是我唯一无法弄清楚的事情。谢谢!
2015年

29

我想出了一种无需添加其他视图的方法:

 [aView addConstraint:[NSLayoutConstraint constraintWithItem:viewOnLeft attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationLessThanOrEqual toItem:aView attribute:NSLayoutAttributeCenterX multiplier:1 constant:0]];
 [aView addConstraint:[NSLayoutConstraint constraintWithItem:viewOnRight attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationLessThanOrEqual toItem:aView attribute:NSLayoutAttributeCenterX multiplier:1 constant:0]];

您还可以更改常量以在视图之间创建间隙。

  • 左视图约束常量: -X
  • 右视图约束常量: +X

居中子视图


很有意思。好的解决方案!
Bob Spryn

实际上,经过更多检查之后,我不太确定您在这里做什么。在这两个子视图周围至少有一个包装器吗?介意分享一个示例项目或阐述您的解释?
Bob Spryn

1
没有包装器,只有一个“ aView”,即包含白球和计数器的矩形。“ viewOnLeft”是白球,“ viewOnRight”是计数器。
Lucien

啊,我明白你在说什么。好的,这是一个很酷的解决方案。现在,我想您甚至可以在代码中不使用“ aView”包装程序的情况下进行操作。
Bob Spryn

16
这似乎使左视图的右侧和右视图的左侧与其容器的中心对齐。如果左侧视图和右侧视图的宽度大致相同,则看起来不错。但是,如果一侧明显宽于另一侧,则肯定会显得不平衡。
EthanB 2013年

16

我花了一些时间,但是我想出了一个非常可靠的解决方案。我想出了约翰·绍尔(John Sauer)提供的相同解决方案,但不想添加另一个视图来封装这些解决方案。

答案需要三个步骤。

1)包含其他两个子视图的子视图的宽度(我称之为leftInfoSection)需要由其内容确定。这样一来,就无需对超级视图(或其他视图)具有左右约束来确定其宽度。这是很多东西的真正关键,就是让孩子们定义宽度。

在此处输入图片说明

2)我仍然必须在IB中有一个领先的约束才能使它具有有效的布局。(它需要知道leftInfoSection水平放置的位置)。将一个约束连接到代码中,以便将其删除。除此之外,我还有一个垂直约束+ 3的约束GTE。

3)最后的关键是考虑必须使用哪些信息(在代码中,因为IB受限制)。我意识到我知道横断面上方的水平分隔线的中心,并且我leftInfoSection的中心就是该水平条的中心减去水平条宽度的1/4。这是左侧和右侧的最终代码:

// remove the unwanted constraint to the right side of the thumbnail
[self.questionBox removeConstraint:self.leftInfoViewLeadingConstraint];
// calculate the center of the leftInfoView
CGFloat left = self.horizontalDividerImageView.frame.size.width/4 * -1;
// constrain the center of the leftInfoView to the horizontal bar center minus a quarter of it to center things
[self.questionBox addConstraint:[NSLayoutConstraint constraintWithItem:self.leftInfoView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.horizontalDividerImageView attribute:NSLayoutAttributeCenterX multiplier:1 constant:left]];

// remove the unwanted constraint to the right side of the questionBox
[self.questionBox removeConstraint:self.rightInfoViewTrailingConstraint];
// calculate the center of the rightInfoView
CGFloat right = left * -1;
// constrain the center of the rightInfoView to the horizontal bar center plus a quarter of it to center things
[self.questionBox addConstraint:[NSLayoutConstraint constraintWithItem:self.rightInfoView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.horizontalDividerImageView attribute:NSLayoutAttributeCenterX multiplier:1 constant:right]];

结果: 最后结果

同样,IB可能会很烦恼它如何自动更新约束。当我尝试将子视图上的前导约束和尾随约束定义为0时,它将不断断开一个或另一个的连接,并对超级视图进行约束以定义宽度。诀窍是暂时将不需要的约束留在原处,但将其优先级降低到999。然后,我可以创建子视图约束来定义宽度。


16

斯坦福大学在ios 7上的演讲中考虑了一种解决方案,它的效果非常好。(这是sdfssfg ...东西是label1,而efsdfg ....东西是label2)

在此处输入图片说明


1
愿意提供进一步的说明吗?
汤米”,2015年

2
基本上,在想要的两个标签(分别说L1和L2)后面附加两个透明的uiviews(分别说V1和V2)。V1和V2应该具有相等的宽度,而所有四个视图都应标为:-V1-L1-L2-V2- 。连字符是它们之间的水平距离(约束)可以是任何值。我建议将其保持为零。
Vinayak Parmar,2015年

我怎么能找到那个演讲?它的数量是多少?
德米特里·L.

6
观看此视频youtube.com/watch?v=pv1EHGEf884(第48分钟之后,他将解释上述问题)
Vinayak Parmar

更简化的答案就在这里给出例子stackoverflow.com/questions/15590196/...
Dashrath

11

这工作得很好,但需要2个spacer UIView:

UIView *spacer1 = [[UIView alloc] init];
spacer1.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:spacer1];

UIView *spacer2 = [[UIView alloc] init];
spacer2.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:spacer2];

NSDictionary *views = NSDictionaryOfVariableBindings(spacer1, spacer2, imageView, label);

[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[spacer1(>=0)][imageView]-4-[label][spacer2(==spacer1)]|" options:0 metrics:nil views:views];

for (int i = 0; i < constraintsArray.count; i++) {

    [self.view addConstraint:constraintsArray[i]];
}

...而且,据记录,我无法仅通过添加imageView.lead = label.trailing约束来使这项工作有效。可能我很胖。
汤米



0

有几种方法可以做到这一点。从根本上讲,这是如何将1..n个商品居中的方法,假设您所有商品的尺寸都受限制并且不会增长

  1. 在物品的每一侧都放2个垫片。将垫片固定到父边缘。将您的第一个和最后一个项目锚定到锚点。最后,分配一个垫片,使其具有另一个垫片的宽度。您无需显式设置任何垫片大小,因为它将解决

    • spacer1-> left = parent:left width = spacer2:width
    • spacer2->右=父母:右
    • yourFirstItem-> left = spacer1:right
    • yourLastItem-> right = spacer2:left
  2. 如果不是您想要的东西,而您和您的物品数量奇数,则将中间的物品居中放置在父物品的中心。另外,请确保第一项和最后一项没有锚定到父边。

    • yourMiddleItem = centerX = parent:centerX
    • otherItems-> yourMiddleItem <-otherItems
  3. 如果不是您想要的东西,而您的物品数量是偶数,则将2个内部物品的边缘居中放置在父对象的中心。另外,请确保第一项和最后一项没有锚定到父边。

    • leftMiddleItem-> right = parent:centerX
    • rightMiddleItem-> left = parent:centerX
    • otherItems-> leftMiddleItem rightMiddleItem <-otherItems
  4. 您还可以将一个不可见的占位符居中居中并固定在该占位符上,但是在约束时您仍然需要考虑奇数/偶数个项目,因此我不建议这种方法。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.