iOS Autolayout вертикально равное пространство для заполнения родительского вида
у меня есть контроллер вида с 12 UITextField
s.
Он очень хорошо подходит для 3,5" дисплей.
мне нужно установить его для iPhone 5 (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" и оставляет пространство ниже.
где я делаю ошибку?
3 ответов
чтобы сделать это с помощью auto layout, необходимо создать дополнительные представления для заполнения пробелов между текстовыми полями.
Напомним, что ограничение автоматической компоновки в основном является линейным уравнением A = m * B + c
. A
является атрибутом одного вида (например, координата Y viewA
's нижняя кромка) и B
является атрибутом другого представления (например, координата Y viewB
верхний край). m
и c
константы. Так, например, выложить viewA
и viewB
так что есть 30 точек между нижней частью viewA
и верхней viewB
, мы могли бы создать ограничение, где m
1 и c
- это -30.
проблема в том, что вы хотите использовать одно и то же значение для c
через 13 различных ограничений, и вы хотите, чтобы автоматический макет вычислял это c
значение для вас. Auto layout просто не может этого сделать. Не напрямую. Автоматический макет может вычислять только атрибуты представлений; он не может вычислить m
и c
константы.
есть способ сделать автоматический макет, чтобы поместить представления, где вы хотите: reify пространства между текстовыми полями как дополнительные (невидимые) представления. Вот пример всего с 3 текстовыми полями:
мы создадим ограничение, чтобы прикрепить верхний край каждой прокладки к нижнему краю текстового поля над ним. Мы также создадим ограничение, чтобы прикрепить нижний край каждой прокладки к верхнему краю текста полем ниже. И, наконец, мы создадим ограничение, чтобы заставить каждую прокладку иметь ту же высоту, что и самая верхняя прокладка.
нам понадобятся две переменные экземпляра для настройки: массив текстовых полей (в порядке сверху вниз) и ссылка на самый верхний вид прокладки:
@implementation ViewController {
NSMutableArray *textFields;
UIView *topSpacer;
}
мы создадим текстовые поля и прокладки в коде, так как трудно показать xib в ответе stackoverflow. Мы пнуть вещи в viewDidLoad
:
- (void)viewDidLoad {
[super viewDidLoad];
self.view.translatesAutoresizingMaskIntoConstraints = NO;
[self addTextFields];
[self addSpacers];
}
так как мы собираемся использовать Auto layout, нам нужно отключить 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];
}
мы будем использовать петлю для создания прокладок тоже, но мы создаем верхние и нижние прокладки по-разному от средних прокладок, потому что нам нужно прикрепить верхние и нижние прокладки к в суперпанель:
- (void)addSpacers {
[self addTopSpacer];
for (int i = 1, count = textFields.count; i < count; ++i) {
[self addSpacerFromBottomOfView:textFields[i - 1]
toTopOfView:textFields[i]];
}
[self addBottomSpacer];
}
вот как мы создаем верхнюю прокладку и устанавливаем ее ограничения. Его верхний край прикреплен к супервизору, а нижний край прикреплен к первому (самому верхнему) текстовому полю. Мы храним верхнюю прокладку в переменной экземпляра 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;
}
вот как мы на самом деле создаем вид пространства. Это просто скрытый вид. Поскольку нас не волнует его горизонтальность размер или положение, мы просто прикрепляем его к левому и правому краям супервизора.
- (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)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)]];
}
если вы сделаете это правильно, вы получите такой результат:
вы можете найти полный пример проекта в этот репозиторий github.
проверить 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;
// ...
см. раздел разработчик.документация apple, которая имеет хорошее описание решения, https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/AutolayoutPG/AutoLayoutbyExample/AutoLayoutbyExample.html см. интервал и деформацию на этой странице, Я думаю, что это хорошее описание, поэтому не нужно объяснять то же самое здесь
редактировать
выше ссылка теперь отключена apple, так как с iOS 9 у них есть введен Stackview, который является решением для всего этого.
ранее в приведенной выше ссылке ответ был таким же, как ответ, предоставленный @rob