iOS自动布局垂直相等空间以填充父视图
我有一个带有12iOS自动布局垂直相等空间以填充父视图,ios,autolayout,Ios,Autolayout,我有一个带有12UITextFields的视图控制器 它非常适合3.5英寸显示屏 我需要为iPhone5(4英寸显示屏)设置它,以便所有的UITextFields都覆盖整个UIView,在它们之间添加额外的空间 我试图通过自动布局来实现这一点,但它不能正常工作 这是我的代码: - (void) viewWillLayoutSubviews { int h = txt1.bounds.size.height * 12; float unusedHorizontalSpace
UITextField
s的视图控制器
它非常适合3.5英寸显示屏
我需要为iPhone5(4英寸显示屏)设置它,以便所有的UITextField
s都覆盖整个UIView
,在它们之间添加额外的空间
我试图通过自动布局来实现这一点,但它不能正常工作
这是我的代码:
- (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];
}
如果我做了[txt12(=txt1)]
,那么它将显示与3.5英寸屏幕相同的内容,并在下面留下空间
我犯了什么错误?要使用自动布局进行此操作,必须创建额外的视图以填充文本字段之间的空间 回想一下,自动布局约束基本上是线性方程
A=m*B+c
<代码>A是一个视图的属性(例如视图A
的底边的Y坐标),而B
是另一个视图的属性(例如视图B
的顶边的Y坐标)m
和c
是常数。因此,例如,要布置viewA
和viewB
,使viewA
的底部和viewB
的顶部之间有30个点,我们可以创建一个约束,其中m
为1,c
为-30
您遇到的问题是,您希望跨13个不同的约束对c
使用相同的值,并且希望auto layout为您计算该c
值。自动布局根本不能做到这一点。不直接。自动布局只能计算视图的属性;它无法计算m
和c
常数
有一种方法可以使自动布局将视图放置在您想要的位置:将文本字段之间的空格具体化为附加(不可见)视图。下面是一个仅包含3个文本字段的示例:
我们将创建一个约束,将每个间隔符的上边缘固定到其上方文本字段的下边缘。我们还将创建一个约束,将每个间隔符的底边固定到其下方文本字段的顶边。最后,我们将创建一个约束,强制每个间隔垫圈与最上面的间隔垫圈具有相同的高度
我们需要两个实例变量来进行设置:一个文本字段数组(按从上到下的顺序排列),以及对最顶部间隔视图的引用:
@implementation ViewController {
NSMutableArray *textFields;
UIView *topSpacer;
}
我们将在代码中创建文本字段和空格,因为在stackoverflow答案中很难显示xib。我们在viewDidLoad
中启动:
- (void)viewDidLoad {
[super viewDidLoad];
self.view.translatesAutoresizingMaskIntoConstraints = NO;
[self addTextFields];
[self addSpacers];
}
由于我们将使用自动布局,我们需要关闭translatesAutoresizingMaskIntoConstraints
,以防止系统创建额外的约束
我们创建每个文本字段,为其提供一些虚拟文本,并为其水平位置和大小设置约束:
- (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];
}
下面是我们实际创建间隔视图的方式。这只是一个隐藏的视图。因为我们不关心它的水平大小或位置,所以我们只是将它固定到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;
}
要在两个文本视图之间创建“中间”分隔符,我们将其固定到文本的底部边缘
上面的字段和下面的文本字段的上边缘。我们还将其高度约束为等于顶部间隔的高度
- (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;
}
- (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)]];
}
- (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)]];
}
要创建底部间隔符,我们将其固定到最后一个文本字段和superview。我们还将其高度约束为等于顶部间隔的高度
- (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;
}
- (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)]];
}
- (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)]];
}
如果你做对了,你会得到这样的结果:
您可以在中找到完整的示例项目。签出。它被设计成在代码中创建自动布局约束的最简单和最友好的API
针对您的具体问题,PureLayout提供了两个主要的API来分布视图,一个是每个视图之间的间距固定(视图大小根据需要而变化),另一个是每个视图的大小固定(视图之间的间距根据需要而变化)。后者不需要使用任何“间隔视图”,就可以完成所需的任务
请参阅developer.apple的文档,其中对解决方案有很好的描述,请参阅该页面中的间距和扭曲,我认为这是很好的描述,因此无需在这里解释相同的内容 编辑 上面的链接现在被苹果禁用,从iOS9开始,他们引入了Stackview,这是解决所有这些问题的解决方案
在前面的链接中,答案与@rob提供的答案相同,在您的
constraintsWithVisualFormat
字符串中,您的第一个“空格”是一个常数50,您只使用了12个“空格”标识符,即使您计算了13个。将50
更改为(空格)
,或将每个按钮之间的空格计算为未使用的水平空格/12-50
。不确定它是否会起作用,但值得一试。你用上面的代码到底得到了什么?@Hari Karam Sing看到第二张图片。哦,我明白了。计算间距,然后将其作为固定值传递。否?您是否检查过该值是否正确计算为Retina4大小的更大值?我有一个很好的解决方案,它不使用间隔符,而是使用IB。[此处][1][1]:感谢这个伟大的答案。我正在尝试转换自动布局,因为我认为它很容易实现。但它似乎只支持两种观点。添加额外的视图还需要内存和处理能力。但我认为没有其他解决办法。不管怎样,谢谢你。这有助于我学到一些东西。我很困惑:“你想让auto layout为你计算c值。auto layout根本做不到。”。如果c
是间距,那么他在代码中明确指定了它……这个答案(不幸)是错误的。您可以在不使用间隔视图的情况下实现所需的效果。在我创建的类别上实现该方法时,可以查看此问题的一般案例解决方案。我的答案不需要固定的文本范围