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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14741713/
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-30 22:10:55  来源:igfitidea点击:

Auto Layout (Constraints) Center 2 side by side views in a parent view

iphoneiosconstraintsautolayout

提问by Bob Spryn

I'm trying to figure out how to do this with auto layout (iOS6) and constraints.

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

Basically I have my large view divided up into two sections on the bottom. Inside of those sections (currently subviews) I have an image view and a label. I want to center those on both sides, with variable length text.

基本上,我的大视图在底部分为两个部分。在这些部分(当前是子视图)中,我有一个图像视图和一个标签。我想用可变长度的文本将它们放在两边。

My head is mostly wrapped around auto layout, but I'm not sure the best approach to this. I'm inclined to think it's not possible in IB, but is in code.

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

Going to continue trying to figure this out, but in the meantime here is the example I'm trying to create.

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

enter image description here

在此处输入图片说明

回答by John Sauer

Is this what you're after?

这是你追求的吗?

short labellong label

短标签长标签

I did it by adding a view (named viewCenteredInLeftSection) within your leftSection, then adding the clock image and label as subviews with these constraints:

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

  • Make viewCenteredInLeftSection's CenterX and CenterY equal to its superview's (leftSection).
  • Make clockImage's Top, Bottom, and Leading edges equal to its superview's (viewCenteredInLeftSection).
  • Make label's Trailing edge equal to its superview's (viewCenteredInLeftSection).
  • Make clockImage's Trailing edge the standard distance away from label's Leading edge.
  • 使viewCenteredInLeftSection的 CenterX 和 CenterY 等于其父视图的 ( leftSection)。
  • 使clockImage的顶部、底部和前缘与其父视图的 ( viewCenteredInLeftSection)相等。
  • 使label的后缘等于其父视图的 ( viewCenteredInLeftSection)。
  • 使clockImage的后缘与 的前缘保持标准距离label

viewCenteredInLeftSection

viewCenteredInLeftSection

I have trouble resizing iOS UIViews in Interface Builder, so I made my example for OS X, and I was able to do so entirely in Interface Builder. If you have trouble making the above constraints in Interface Builder, let me know, and I'll post code that'll create them.

我无法在 Interface Builder 中调整 iOS UIViews 的大小,因此我为 OS X 制作了示例,并且我能够完全在 Interface Builder 中完成此操作。如果您在 Interface Builder 中创建上述约束时遇到问题,请告诉我,我将发布创建它们的代码。

2014-08-26 Edit

2014-08-26 编辑

Luda, here are Xcode 5's Pin and Align menus, also available in Xcode's menu bar:

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

Align menuPin menu

对齐菜单固定菜单

Below is what my example looks like in Interface Builder. The blue view is the "parent view" from the original question, the given view in which the image and label should be centered.

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

I added the green view (which I named viewCenteredInLeftSection) as a subview of "parent view". Then I highlighted it and used the Align menus "Horizontal Center in Container" and "Vertical Center in Container" to create constraints to define its position.

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

I added the clock image as a subview of viewCenteredInLeftSection, with constraints defining its width and height. I highlighted the clock image and viewCenteredInLeftSection, then applied constraints using Align > Leading Edges, Align > Top Edges, and Align > Bottom Edges.

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

I added the label as a subview of viewCenteredInLeftSection, positioning it to be the standard Aqua space distancefrom the clock image. I highlighted the label and viewCenteredInLeftSection, then applied constraints using Align > Trailing Edges.

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

This was mucheasier to create with Xcode 5's Interface Builder versus Xcode 4's.

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

Interface Builder

界面生成器

回答by Lucien

I figured out a way without adding another view:

我想出了一种不添加另一个视图的方法:

 [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]];

You can also change the constants to create a gap between the views.

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

  • left view constraint constant: -X
  • right view constraint constant: +X
  • 左视图约束常量: -X
  • 右视图约束常数: +X

centering subviews

居中子视图

回答by Bob Spryn

It took me a little while, but I figured out a pretty solid solution. I figured out the same solution John Sauer provided, but didn't want to add yet another view to wrap these in.

我花了一点时间,但我想出了一个非常可靠的解决方案。我想出了 John Sauer 提供的相同解决方案,但不想添加另一个视图来包装这些。

The answer requires three steps.

答案需要三个步骤。

1) The width of my subview that contains the other two, which I'll call leftInfoSection, needs to be determined by it's contents. That removes the need for it to have left and right constraints to a superview (or other view) to determine it's width. That's a real key with a lot of this stuff is letting widths be defined by children.

1) 包含另外两个的子视图的宽度,我将称之为leftInfoSection,需要由它的内容来确定。这消除了对超级视图(或其他视图)的左右约束来确定其宽度的需要。很多这些东西的真正关键是让宽度由孩子定义。

enter image description here

在此处输入图片说明

2) I still had to have a leading constraint in IB for it to have a valid layout. (It needed to know where to place the leftInfoSectionhorizontally). Wire up that one constraint into your code so you can remove it. In addition to that, I had a trailing constraint GTE the vertical divider + 3.

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

3) The final key is to think about what information you have to work with (in code, as IB is limited). I realized that I knew the center of the horizontal divider above my section, and that the center of my leftInfoSectionwould be the center of that horizontal bar minus 1/4 of the horizontal bar's width. Here's the final code for both the left and right side:

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]];

Result:Final result

结果:最后结果

Also, IB can be very annoying with how it automatically updates constraints. When I was trying to define the leading and trailing constraints on the subviews as 0, it would keep disconnecting one or the other and making a constraint to the superview to define the width. The trick was to leave that unwanted constraint in place temporarily, but lower its priority to 999. Then I was able to create but subview constraints to define the width.

此外,IB 可能会因为它如何自动更新约束而非常烦人。当我试图将子视图上的前导和尾随约束定义为 0 时,它会不断断开一个或另一个,并对超级视图进行约束以定义宽度。诀窍是暂时保留不需要的约束,但将其优先级降低到 999。然后我可以创建子视图约束来定义宽度。

回答by Vinayak Parmar

A solution to this is considered in stanford university lectures on ios 7.It works beautifully.Attached here that solution. (Here sdfssfg... thing is label1 and efsdfg.... thing is label2)

在关于 ios 7 的斯坦福大学讲座中考虑了一个解决方案。它工作得很好。附在这里解决方案。(这里 sdfssfg...东西是 label1 和 efsdfg....东西是 label2)

enter image description here

在此处输入图片说明

回答by Christian

This works pretty well but requires 2 spacer UIView's:

这很好用,但需要 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]];
}

回答by alcamla

After iOS 9, another option to achieve this is using Stack Views

在 iOS 9 之后,实现此目的的另一种选择是使用Stack Views

回答by Steven Spungin

There are several ways to do this. In basic terms, here is how to center 1..n items, assuming all your items have constrained sizes and are not going to grow.

有几种方法可以做到这一点。基本上,这里是如何将 1..n 个项目居中,假设您的所有项目的大小都受到限制并且不会增长

  1. Put 2 spacers on each side of your items. Anchor the spacers to the parent edges. Anchor your first and last items to the anchors. Finally, assign 1 spacer to have the width of the other spacer. You do not need to explicitly set any spacer size, as it will be solved.

    • spacer1 -> left=parent:left width=spacer2:width
    • spacer2 -> right=parent:right
    • yourFirstItem -> left=spacer1:right
    • yourLastItem -> right=spacer2:left
  2. If spacers aren't your thing, and you and you have an odd number of items, center the middle one to the center of the parent. Also, make sure the first and last items are not anchored to the parent edges.

    • yourMiddleItem = centerX=parent:centerX
    • otherItems->yourMiddleItem<-otherItems
  3. If spacers aren't your thing, and you have an even number of items, center the 2 inner items' edges to the center of the parent. Also, make sure the first and last items are not anchored to the parent edges.

    • leftMiddleItem -> right=parent:centerX
    • rightMiddleItem -> left=parent:centerX
    • otherItems->leftMiddleItem rightMiddleItem<-otherItems
  4. You can also center an invisible placeholder in the center, and anchor to that, but you will still need to consider an odd/even number of items when constraining, so I don't recommend that approach.

  1. 在物品的每一侧放置 2 个垫片。将垫片锚定到父边缘。将您的第一个和最后一个项目锚定到锚点。最后,分配 1 个垫片以具有另一个垫片的宽度。您不需要明确设置任何间隔大小,因为它会被解决

    • 间隔1 -> 左=父:左宽度=间隔2:宽度
    • 间隔2 -> 右=父:右
    • 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 Amitg2k12

You might want to refer this

你可能想参考这个

Percentage based marking

基于百分比的标记

Basically, it says first being with the some incorrect margin and then correct it wrt to its parent view.

基本上,它说首先使用一些不正确的边距,然后将其纠正到其父视图。

Working with my case.

处理我的案例。