我有一个12 UITextField秒的视图控制器.
它非常适合3.5"显示屏.

我需要将其设置为iPhone 5(4英寸显示屏),以便通过在两者之间增加额外空间来UITextField覆盖整体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];
}
Run Code Online (Sandbox Code Playgroud)
如果我这样做,[txt12(==txt1)]它显示与3.5"屏幕相同,并在下面留下空间.
我在哪里弄错了?
rob*_*off 49
要使用自动布局执行此操作,您必须创建额外的视图以填充文本字段之间的空格.
回想一下,自动布局约束基本上是线性方程A = m * B + c. A是一个视图的属性(例如,viewA下边缘的Y坐标),B是另一个视图的属性(例如,viewB上边缘的Y坐标). m并且c是常数.因此,例如,要布局viewA并且viewB在底部viewA和顶部之间有30个点viewB,我们可以创建一个约束,其中m是1并且c是-30.
您遇到的问题是您希望c在13个不同的约束中使用相同的值,并且您希望自动布局c为您计算该值.自动布局根本无法做到这一点.不是直接的.自动布局只能计算视图的属性; 它无法计算m和c常量.
有一种方法可以使自动布局将视图放在您想要的位置:将文本字段之间的空格重新作为附加(不可见)视图.这是一个只有3个文本字段的示例:
我们将创建一个约束来将每个spacer的顶部边缘固定到它上面的文本字段的底部边缘.我们还将创建一个约束,将每个spacer的底边固定到它下面的文本字段的顶边.最后,我们将创建一个约束来强制每个间隔物具有与最顶部间隔物相同的高度.
我们需要一个两个实例变量来设置:文本字段的数组(按从上到下的顺序),以及对最顶层spacer视图的引用:
@implementation ViewController {
NSMutableArray *textFields;
UIView *topSpacer;
}
Run Code Online (Sandbox Code Playgroud)
我们将在代码中创建文本字段和间隔符,因为很难在stackoverflow答案中显示xib.我们开始了viewDidLoad:
- (void)viewDidLoad {
[super viewDidLoad];
self.view.translatesAutoresizingMaskIntoConstraints = NO;
[self addTextFields];
[self addSpacers];
}
Run Code Online (Sandbox Code Playgroud)
由于我们将使用自动布局,因此我们需要关闭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];
}
Run Code Online (Sandbox Code Playgroud)
我们也将使用一个循环来创建间隔物,但是我们创建顶部和底部间隔物的方式与中间间隔物不同,因为我们需要将顶部和底部间隔物固定到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];
}
Run Code Online (Sandbox Code Playgroud)
以下是我们如何创建顶部间隔并设置其约束.其上边缘固定在superview上,其下边缘固定在第一个(最顶部)文本字段上.我们将顶部垫片存储在实例变量中,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;
}
Run Code Online (Sandbox Code Playgroud)
这是我们实际创建间隔视图的方式.这只是一个隐藏的视图.由于我们不关心其水平尺寸或位置,我们只需将其固定在超视图的左右边缘.
- (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;
}
Run Code Online (Sandbox Code Playgroud)
要在两个文本视图之间创建"中间"间隔,我们将其固定到上方文本字段的下边缘和下方文本字段的上边缘.我们还将其高度限制为等于顶部间隔物的高度.
- (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)]];
}
Run Code Online (Sandbox Code Playgroud)
要创建底部间隔符,我们将其固定到最后一个文本字段和超级视图.我们还将其高度限制为等于顶部间隔物的高度.
- (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)]];
}
Run Code Online (Sandbox Code Playgroud)
如果你做对了,你会得到这样的结果:
您可以在此github存储库中找到完整的示例项目.
smi*_*org 10
看看PureLayout.它被设计为最简单,程序最友好的API,可用于在代码中创建自动布局约束.
响应于您的具体问题,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;
// ...
Run Code Online (Sandbox Code Playgroud)