基本上,我将我的大视图分成了底部的两个部分。在这些部分内(目前是子视图),我有一个图像视图和一个标签。我想让它们在两侧居中,并具有可变长度的文本。
我的头脑主要围绕着自动布局,但我不确定最佳方法是什么。我倾向于认为这在IB中不可能,但在代码中可以实现。
我将继续尝试解决这个问题,但同时,这里是我要创建的示例。
这是您想要的内容吗?
我通过在leftSection
中添加一个视图(命名为viewCenteredInLeftSection
),然后将时钟图片和标签作为子视图添加,并使用以下约束来完成:
viewCenteredInLeftSection
的CenterX和CenterY等于其父视图(即leftSection
)。clockImage
的顶部、底部和前缘与其父视图(即viewCenteredInLeftSection
)相等。label
的后缘与其父视图(即viewCenteredInLeftSection
)相等。clockImage
的后缘与label
的前缘相隔标准距离。我在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
,然后使用对齐>尾缘应用约束。我找到了一种方法,而不需要添加另一个视图:
[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
po [[UIWindow keyWindow] _autolayoutTrace]
,LLDB 将告诉您是否存在布局不明确的情况。 - mon4goos斯坦福大学在iOS 7的讲座中提供了一种解决方案,该方案非常有效。在此附上该解决方案。(这里 sdfssfg... 的东西是 label1,efsdfg.... 的东西是 label2)
花了一点时间,但我找到了一个相当可靠的解决方案。我发现了John Sauer提供的相同解决方案,但不想再添加一个视图来包装这些内容。
答案需要三个步骤。
1)包含其他两个子视图的子视图(我称之为leftInfoSection
)的宽度需要由其内容确定。这就避免了需要将其左右约束到父视图(或其他视图)以确定其宽度的需求。其中很重要的一点是让宽度由子视图定义。
2)我仍然需要在IB中拥有一个前导约束,以使其具有有效布局。(它需要知道如何水平放置leftInfoSection
)。将那个约束连接到你的代码中,这样你就可以删除它。除此之外,我还有一个大于等于垂直分隔线+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]];
}
imageView
.leading = label
.trailing来实现此功能,但并未成功。可能是我太蠢了。 - Tommy有几种方法可以做到这一点。简单来说,以下是如何居中1..n个项目的步骤,假设所有项目都具有约束大小并且不会增长。
在您的项目两侧放置2个间隔块。将间隔块锚定到父边缘。将您的第一个和最后一个项目锚定到这些间隔块上。最后,分配1个间隔块具有另一个间隔块的宽度。您不需要显式设置任何间隔块大小,因为它会被“解决”。
如果您不喜欢使用间隔块,并且您的项目数量是奇数,请将中间的项目居中对齐到父级中心。同时,请确保第一个和最后一个项目没有锚定到父边缘。
如果您不喜欢使用间隔块,并且您的项目数量是偶数,请将2个内部项目的边缘居中对齐到父级中心。同时,请确保第一个和最后一个项目没有锚定到父边缘。
您还可以在中心处居中一个不可见的占位符,并将其锚定到该位置,但是在约束时仍需要考虑奇数/偶数项目,因此我不建议使用这种方法。