iOS Autolayout 垂直等间距填充父视图
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17089427/
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
iOS Autolayout Vertically equal space to fill parent view
提问by CRDave
I have a view controller with 12 UITextField
s.
我有一个 12UITextField
秒的视图控制器。
It fits a 3.5" display very well.
它非常适合 3.5" 显示器。
I need to set it for iPhone 5 (4 inch display) such that all UITextField
s cover the whole UIView
by adding extra space in between.
我需要为 iPhone 5(4 英寸显示屏)设置它,以便通过在它们之间添加额外空间来UITextField
覆盖整个屏幕UIView
。
I am trying to do this by auto layout but it is not working properly.
我试图通过自动布局来做到这一点,但它无法正常工作。
This is my code :
这是我的代码:
- (void) viewWillLayoutSubviews
{
int h = txt1.bounds.size.height * 12;
float unusedHorizontalSpace = self.view.bounds.size.height - h ;
NSNumber* spaceBetweenEachButton= [NSNumber numberWithFloat: unusedHorizontalSpace / 13 ] ;
NSMutableArray *constraintsForButtons = [[NSMutableArray alloc] init];
[constraintsForButtons addObjectsFromArray: [NSLayoutConstraint constraintsWithVisualFormat: @"V:|-50-[txt1(==30)]-(space)-[txt2(==txt1)]-(space)-[txt3(==txt1)]-(space)-[txt4(==txt1)]-(space)-[txt5(==txt1)]-(space)-[txt6(==txt1)]-(space)-[txt7(==txt1)]-(space)-[txt8(==txt1)]-(space)-[txt9(==txt1)]-(space)-[txt10(==txt1)]-(space)-[txt11(==txt1)]-(space)-[txt12]-(space)-|"
options: NSLayoutFormatAlignAllCenterX
metrics: @{@"space":spaceBetweenEachButton}
views: NSDictionaryOfVariableBindings(txt1,txt10,txt11,txt12,txt2,txt3,txt4,txt5,txt6, txt7,txt8,txt9)]];
[self.view addConstraints:constraintsForButtons];
}
If I do [txt12(==txt1)]
then it displays the same as the 3.5" screen and leaves space below.
如果我这样做,[txt12(==txt1)]
它会显示与 3.5" 屏幕相同的屏幕并在下方留出空间。
Where I am making a mistake?
我在哪里犯了错误?
回答by rob mayoff
To do this with auto layout, you must create extra views to fill the spaces between the text fields.
要使用自动布局来做到这一点,您必须创建额外的视图来填充文本字段之间的空间。
Recall that an auto layout constraint is basically the linear equation A = m * B + c
. A
is an attribute of one view (for example, the Y coordinate of viewA
's bottom edge) and B
is an attribute of another view (for example, the Y coordinate of viewB
's top edge). m
and c
are constants. So, for example, to lay out viewA
and viewB
so that there are 30 points between the bottom of viewA
and the top of viewB
, we could create a constraint where m
is 1 and c
is -30.
回想一下,自动布局约束基本上是线性方程A = m * B + c
。 A
是一个视图的属性(例如,viewA
的下边缘的 Y 坐标)和B
另一个视图的属性(例如,viewB
的上边缘的 Y 坐标)。 m
并且c
是常数。因此,例如,要进行布局viewA
并使viewB
的底部viewA
和顶部之间有 30 个点viewB
,我们可以创建一个约束,其中m
1 和c
-30。
The problem you're having is that you want to use the same value for c
across 13 different constraints, and you want auto layout to compute that c
value for you. Auto layout simply can't do that. Not directly. Auto layout can only compute the attributes of views; it cannot compute the m
and c
constants.
您遇到的问题是您想对c
13 个不同的约束使用相同的值,并且您希望自动布局c
为您计算该值。自动布局根本无法做到这一点。不直接。自动布局只能计算视图的属性;它不能计算m
和c
常数。
There is a way to make auto layout put the views where you want: reify the spaces between the text fields as additional (invisible) views. Here's an example with just 3 text fields:
有一种方法可以让自动布局将视图放在您想要的位置:将文本字段之间的空间具体化为附加(不可见)视图。这是一个只有 3 个文本字段的示例:
We'll create a constraint to pin each spacer's top edge to the bottom edge of the text field above it. We'll also create a constraint to pin each spacer's bottom edge to the top edge of the text field below it. And finally, we'll create a constraint to force each spacer to have the same height as the topmost spacer.
我们将创建一个约束来将每个间隔的顶部边缘固定到其上方文本字段的底部边缘。我们还将创建一个约束,将每个间隔器的底部边缘固定到其下方文本字段的顶部边缘。最后,我们将创建一个约束来强制每个垫片与最上面的垫片具有相同的高度。
We'll need a two instance variables to set things up: an array of the text fields (in order from top to bottom), and a reference to the topmost spacer view:
我们需要两个实例变量来进行设置:一个文本字段数组(按从上到下的顺序),以及对最上面的间隔视图的引用:
@implementation ViewController {
NSMutableArray *textFields;
UIView *topSpacer;
}
We'll create the text fields and spacers in code since it's hard to show a xib in a stackoverflow answer. We kick things off in viewDidLoad
:
我们将在代码中创建文本字段和间隔符,因为很难在 stackoverflow 答案中显示 xib。我们开始viewDidLoad
:
- (void)viewDidLoad {
[super viewDidLoad];
self.view.translatesAutoresizingMaskIntoConstraints = NO;
[self addTextFields];
[self addSpacers];
}
Since we're going to use auto layout, we need to turn off translatesAutoresizingMaskIntoConstraints
to prevent the system from creating extra constraints.
由于我们将使用自动布局,我们需要关闭translatesAutoresizingMaskIntoConstraints
以防止系统创建额外的约束。
We create each text field, give it some dummy text, and set up constraints for its horizontal position and size:
我们创建每个文本字段,给它一些虚拟文本,并为其水平位置和大小设置约束:
- (void)addTextFields {
textFields = [NSMutableArray array];
for (int i = 0; i < 12; ++i) {
[self addTextField];
}
}
- (void)addTextField {
UITextField *field = [[UITextField alloc] init];
field.backgroundColor = [UIColor colorWithHue:0.8 saturation:0.1 brightness:0.9 alpha:1];
field.translatesAutoresizingMaskIntoConstraints = NO;
field.text = [field description];
[self.view addSubview:field];
[field setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
[field setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|-[field]-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(field)]];
[textFields addObject:field];
}
We'll use a loop to create the spacers too, but we create the top and bottom spacers differently from the middle spacers, because we need to pin the top and bottom spacers to the superview:
我们也将使用循环来创建间隔,但我们创建顶部和底部间隔与中间间隔不同,因为我们需要将顶部和底部间隔固定到超级视图:
- (void)addSpacers {
[self addTopSpacer];
for (int i = 1, count = textFields.count; i < count; ++i) {
[self addSpacerFromBottomOfView:textFields[i - 1]
toTopOfView:textFields[i]];
}
[self addBottomSpacer];
}
Here's how we create the top spacer and set up its constraints. Its top edge is pinned to the superview and its bottom edge is pinned to the first (topmost) text field. We store the top spacer in the instance variable topSpacer
so we can constrain the other spacers to have the same height as the top spacer.
下面是我们如何创建顶部间隔器并设置其约束。它的顶边被固定到父视图,它的底边被固定到第一个(最上面的)文本字段。我们将顶部间隔器存储在实例变量中,topSpacer
以便我们可以约束其他间隔器与顶部间隔器具有相同的高度。
- (void)addTopSpacer {
UIView *spacer = [self newSpacer];
UITextField *field = textFields[0];
[self.view addConstraints:[NSLayoutConstraint
constraintsWithVisualFormat:@"V:|[spacer][field]" options:0 metrics:nil
views:NSDictionaryOfVariableBindings(spacer, field)]];
topSpacer = spacer;
}
Here's how we actually create a spacer view. It's just a hidden view. Since we don't care about its horizontal size or position, we just pin it to the left and right edges of the superview.
这是我们实际创建间隔视图的方式。这只是一个隐藏的视图。由于我们不关心它的水平尺寸或位置,我们只是将它固定在超级视图的左右边缘。
- (UIView *)newSpacer {
UIView *spacer = [[UIView alloc] init];
spacer.hidden = YES; // Views participate in layout even when hidden.
spacer.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:spacer];
[self.view addConstraints:[NSLayoutConstraint
constraintsWithVisualFormat:@"|[spacer]|" options:0 metrics:nil
views:NSDictionaryOfVariableBindings(spacer)]];
return spacer;
}
To create a “middle” spacer between two text views, we pin it to the bottom edge of the text field above and the top edge of the text field below. We also constrain its height to equal the height of the top spacer.
为了在两个文本视图之间创建一个“中间”间隔,我们将它固定到上面文本字段的底部边缘和下面文本字段的顶部边缘。我们还将其高度限制为等于顶部垫片的高度。
- (void)addSpacerFromBottomOfView:(UIView *)overView toTopOfView:(UIView *)underView {
UIView *spacer = [self newSpacer];
[self.view addConstraints:[NSLayoutConstraint
constraintsWithVisualFormat:@"V:[overView][spacer(==topSpacer)][underView]" options:0 metrics:nil
views:NSDictionaryOfVariableBindings(spacer, overView, underView, topSpacer)]];
}
To create the bottom spacer, we pin it to the last text field and to the superview. We also constrain its height to equal the height of the top spacer.
为了创建底部间隔,我们将它固定到最后一个文本字段和超级视图。我们还将其高度限制为等于顶部垫片的高度。
- (void)addBottomSpacer {
UIView *spacer = [self newSpacer];
UITextField *field = textFields.lastObject;
[self.view addConstraints:[NSLayoutConstraint
constraintsWithVisualFormat:@"V:[field][spacer(==topSpacer)]|" options:0 metrics:nil
views:NSDictionaryOfVariableBindings(spacer, field, topSpacer)]];
}
If you do it right, you will get a result like this:
如果你做对了,你会得到这样的结果:
You can find a complete example project in this github repository.
您可以在此 github 存储库中找到完整的示例项目。
回答by smileyborg
Check out PureLayout. It's designed to be the simplest and most programmer-friendly API possible for creating Auto Layout constraints in code.
查看PureLayout。它旨在成为在代码中创建自动布局约束的最简单且对程序员最友好的 API。
In response to your specific question, PureLayout offers a two primary APIs for distributing views, one where the spacing between each view is fixed (view size varies as needed), and the other where the size of each view is fixed (spacing between views varies as needed). The latter will accomplish what you're looking for withoutthe use of any "spacer views".
针对您的具体问题,PureLayout 提供了两个主要的视图分发 API,一个是每个视图之间的间距是固定的(视图大小根据需要而变化),另一个是每个视图的大小是固定的(视图之间的间距不同)如所须)。后者将在不使用任何“间隔视图”的情况下完成您正在寻找的内容。
// NSArray+PureLayout.h
// ...
/** Distributes the views in this array equally along the selected axis in their superview. Views will be the same size (variable) in the dimension along the axis and will have spacing (fixed) between them. */
- (NSArray *)autoDistributeViewsAlongAxis:(ALAxis)axis
alignedTo:(ALAttribute)alignment
withFixedSpacing:(CGFloat)spacing;
/** Distributes the views in this array equally along the selected axis in their superview. Views will be the same size (fixed) in the dimension along the axis and will have spacing (variable) between them. */
- (NSArray *)autoDistributeViewsAlongAxis:(ALAxis)axis
alignedTo:(ALAttribute)alignment
withFixedSize:(CGFloat)size;
// ...
回答by Mehul Thakkar
see developer.apple' documentation, that is having nice description about the solution, https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/AutolayoutPG/AutoLayoutbyExample/AutoLayoutbyExample.htmlsee the spacing and warping in that page, i think that is nice description, so no need to explain same thing over here
请参阅 developer.apple 的文档,该文档对解决方案有很好的描述,https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/AutolayoutPG/AutoLayoutbyExample/AutoLayoutbyExample.html查看其中的间距和翘曲页面,我认为这是很好的描述,所以不需要在这里解释同样的事情
EDIT
编辑
Above link is now get disabled by apple, As from iOS 9, they have introduced Stackview, which is solution for all this.
上面的链接现在被苹果禁用了,从 iOS 9 开始,他们引入了 Stackview,这是所有这些的解决方案。
Previously in above link the answer was same as answer provided by @rob
以前在上面的链接中,答案与@rob 提供的答案相同