2013-06-13 4 views
14

У меня есть контроллер вида с 12 UITextField.iOS Autolayout Вертикально равное пространство для заполнения родительского вида

Это соответствует дисплей 3.5" очень хорошо.

enter image description here

Мне нужно установить его для iPhone 5 (4-дюймовый дисплей) таким образом, что все UITextField s покрывают весь UIView путем добавления дополнительного пространства между .

Я пытаюсь сделать это с помощью автоматической компоновки, но он не работает должным образом.

enter image description here

Это мой код:

- (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" экраном и оставляет пространство ниже.

Где я совершаю ошибку?

+0

В вашей 'строки constraintsWithVisualFormat', ваше первое«пространство»является константой 50, и вы используете только 12«космические»идентификаторы , хотя вы рассчитали 13. Либо измените значение '50' на' (пробел) ', либо вычислите' spaceBetweenEachButton' как 'unusedHorizontalSpace/12-50. Не уверен, что это сработает, но это стоит того. –

+0

Что вы на самом деле получаете с кодом выше? –

+0

@ Хэри Карам Синг См. Второе изображение в вопросе. – CRDave

ответ

49

Чтобы сделать это с помощью автоматического макета, вы должны создать дополнительные представления, чтобы заполнить пробелы между текстовыми полями.

Напомним, что ограничение автоматической компоновки в основном является линейным уравнением A = m * B + c. A - это атрибут одного вида (например, координата Y от нижнего края viewA) и B - это атрибут другого вида (например, координата Y верхнего края viewB). m и c являются константами. Так, например, чтобы выложить viewA и viewB, так что есть 30 точек между дном viewA и вершиной viewB, мы могли бы создать ограничение, где m равно 1 и c -30.

Проблема, с которой вы сталкиваетесь, заключается в том, что вы хотите использовать одно и то же значение для c через 13 различных ограничений, и вы хотите, чтобы автоматический макет вычислил, что значение c для вас. Автоматический макет просто не может этого сделать. Не напрямую. Автомакет может вычислять только атрибуты представлений; он не может вычислить константы m и c.

Существует способ сделать автоматическую компоновку, поместите взгляды туда, где вы хотите: обновить пробелы между текстовыми полями как дополнительные (невидимые) виды. Вот пример только с 3 текстовых полей:

example layout

Мы создадим ограничение приколоть верхний край каждой распорки к нижнему краю текстового поля над ним. Мы также создадим ограничение, чтобы прикрепить нижний край каждого разделителя к верхнему краю текстового поля под ним. И, наконец, мы создадим ограничение, чтобы заставить каждую прокладку иметь ту же высоту, что и самая верхняя проставка.

Нам понадобится две переменные экземпляра, чтобы установить вещи: массив текстовых полей (в порядке сверху вниз), а также ссылку на верхний взгляд распорной:

@implementation ViewController { 
    NSMutableArray *textFields; 
    UIView *topSpacer; 
} 

Мы» ll создайте текстовые поля и разделители в коде, так как трудно показать xib в ответе stackoverflow.Мы пнуть вещи в 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]; 
} 

Мы будем использовать цикл для создания распорки тоже, но мы создаем верхние и нижние распорки в отличии от средних прокладок, потому что мы должны прикрепить верхние и нижние распорки к надтаблице:

- (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)]]; 
} 

Если вы сделаете это правильно, вы получите результат, как это:

example code screen shot

Вы можете найти полный пример проекта в this github repository.

+0

Спасибо за этот великий ответ. – CRDave

+0

Я пытаюсь перейти на автоматический макет, думая, что его будет легко реализовать. Но он очень сильно поддерживает только два взгляда. И добавление дополнительного представления также требует памяти и мощности процесса. Но я думаю, что другого решения нет. Так что спасибо за это. Это помогает мне чему-то научиться. – CRDave

+0

Я смущен: «вы хотите, чтобы авто макет вычислил это значение c для вас. Автоматический макет просто не может этого сделать». Если 'c' - это интервал, то он явно укажет его в своем коде ... –

9

Отъезд PureLayout. Он разработан, чтобы быть самым простым и удобным для программистов API, который может создавать ограничения Auto Layout в коде.

В соответствии с вашим конкретным вопросом 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; 

// ... 
+0

Я попробую. Похоже, вы хорошо поработали. Попробуйте поместить его на www.cocoacontrols.com и cocoapods.org, чтобы больше людей могли это видеть. – CRDave

+2

Спасибо! Я обязательно это сделаю.Пожалуйста, не стесняйтесь, дайте мне знать, если у вас есть вопросы, отзывы, предложения или найти ошибки! – smileyborg

2

см. Разработчик.документаций компании Apple, то есть имеющая хорошее описание о решении, https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/AutolayoutPG/AutoLayoutbyExample/AutoLayoutbyExample.html см расстояния и короблении в этой странице, я думаю, что это хорошее описание, так что нет необходимости объяснять то же самое здесь

EDIT

Выше ссылка теперь отключена яблоком. Начиная с iOS 9, они представили Stackview, что является решением для всего этого.

Ранее в ссылке выше, ответ был таким же, как ответ, @rob

+0

: <ссылка прошла плохо –

+0

да, я знаю ... Apple теперь обновил этот документ. Теперь для этого равномерного интервала они представили UIStackview. Итак, теперь не требуется размещать spacerViews (которые были описаны в этой ссылке) .. теперь вы можете легко достичь такой же задачи, используя UIStackviews –

+0

Объяснение по этой ссылке почти такое же, как ответ rob. Поэтому, если вы хотите поддерживать версию ios старше iOS 9, вам нужно пройти только по этой дороге –

Смежные вопросы