我试图弄清楚如何使用自动布局(iOS6)和约束来做到这一点。
基本上,我的大视图在底部分为两个部分。在这些部分(当前为子视图)中,我有一个图像视图和一个标签。我想用可变长度的文本将它们放在两边的中心。
我的头主要是围绕自动布局,但我不确定最好的方法。我倾向于认为这在 IB 中是不可能的,但在代码中是不可能的。
将继续尝试解决这个问题,但与此同时,这是我正在尝试创建的示例。
我试图弄清楚如何使用自动布局(iOS6)和约束来做到这一点。
基本上,我的大视图在底部分为两个部分。在这些部分(当前为子视图)中,我有一个图像视图和一个标签。我想用可变长度的文本将它们放在两边的中心。
我的头主要是围绕自动布局,但我不确定最好的方法。我倾向于认为这在 IB 中是不可能的,但在代码中是不可能的。
将继续尝试解决这个问题,但与此同时,这是我正在尝试创建的示例。
这就是你所追求的吗?
我通过viewCenteredInLeftSection
在您的 中添加一个视图(名为 )leftSection
,然后将时钟图像和标签添加为具有这些约束的子视图来做到这一点:
viewCenteredInLeftSection
的 CenterX 和 CenterY 等于其父视图的 ( leftSection
)。clockImage
的顶部、底部和前缘等于其父视图的 ( viewCenteredInLeftSection
)。label
的后沿等于其父视图的 ( viewCenteredInLeftSection
)。clockImage
's Trailing edge 设为距 'sleading edge 的标准距离label
。我在 Interface Builder 中调整 iOS UIViews 的大小时遇到了麻烦,所以我为 OS X 制作了我的示例,并且我能够完全在 Interface Builder 中这样做。如果您在 Interface Builder 中制作上述约束时遇到问题,请告诉我,我将发布创建它们的代码。
2014-08-26 编辑
Luda,这里是 Xcode 5 的 Pin 和 Align 菜单,也可以在 Xcode 的菜单栏中找到:
下面是我的示例在 Interface Builder 中的样子。蓝色视图是原始问题的“父视图”,即图像和标签应居中的给定视图。
我将绿色视图(我命名为viewCenteredInLeftSection
)添加为“父视图”的子视图。然后我突出显示它并使用对齐菜单“容器中的水平中心”和“容器中的垂直中心”来创建约束来定义其位置。
我将时钟图像添加为 的子视图viewCenteredInLeftSection
,并带有定义其宽度和高度的约束。我突出显示了时钟图像viewCenteredInLeftSection
,然后使用 Align > Leading Edges、Align > Top Edges 和 Align > Bottom Edges 应用约束。
我将标签添加为 的子视图viewCenteredInLeftSection
,将其定位为距时钟图像的标准 Aqua 空间距离。我突出显示了标签viewCenteredInLeftSection
,然后使用对齐 > 后沿应用了约束。
与 Xcode 4 相比,使用 Xcode 5的Interface Builder更容易创建。
我想出了一个不添加另一个视图的方法:
[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
斯坦福大学关于 ios 7 的讲座中考虑了一个解决方案。它工作得很好。附上这个解决方案。(这里 sdfssfg... 东西是 label1 和 efsdfg.... 东西是 label2)
我花了一点时间,但我想出了一个非常可靠的解决方案。我想出了 John Sauer 提供的相同解决方案,但不想添加另一个视图来包装它们。
答案需要三个步骤。
1) 包含其他两个的子视图的宽度,我称之为leftInfoSection
,需要由它的内容来确定。这消除了它对超级视图(或其他视图)具有左右约束以确定其宽度的需要。这是一个真正的关键,其中很多东西是让孩子定义宽度。
2)我仍然必须在 IB 中有一个领先的约束,它才能有一个有效的布局。(它需要知道leftInfoSection
水平放置的位置)。将该约束连接到您的代码中,以便您可以删除它。除此之外,我还有一个尾随约束 GTE 垂直分隔线 + 3。
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。然后我能够创建子视图约束来定义宽度。
这很好用,但需要 2 个间隔 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]];
}
在 iOS 9 之后,实现此目的的另一个选择是使用Stack Views
有几种方法可以做到这一点。基本来说,这里是如何将 1..n 个项目居中,假设所有项目的大小都受到限制并且不会增长。
在物品的每一侧放置 2 个垫片。将垫片锚定到父边。将您的第一个和最后一个项目锚定到锚点上。最后,指定 1 个垫片具有另一个垫片的宽度。您不需要显式设置任何垫片大小,因为它将被解决。
如果垫片不是您的东西,并且您和您有奇数个项目,则将中间一个放在父项的中心。此外,请确保第一个和最后一个项目没有锚定到父边缘。
如果垫片不是您的东西,并且您有偶数个项目,则将 2 个内部项目的边缘居中到父项的中心。此外,请确保第一个和最后一个项目没有锚定到父边缘。
你也可以在中心放置一个不可见的占位符,并锚定到该位置,但是在约束时你仍然需要考虑奇数/偶数的项目,所以我不推荐这种方法。