Центрування подання у його огляді за допомогою мови візуального формату


160

Я щойно почав вивчати автоматичну розкладку для iOS і ознайомився з мовою візуального формату.

Все працює добре, за винятком однієї речі: я просто не можу отримати погляд на центр у межах його нагляду.
Чи можливо це за допомогою VFL чи мені потрібно вручну створити обмеження?

Відповіді:


232

Наразі ні, не виглядає так, що в центрі подання можна переглянути центри, використовуючи лише VFL. Однак це не так складно зробити за допомогою одного рядка VFL та одного додаткового обмеження (на вісь):

VFL: "|-(>=20)-[view]-(>=20)-|"

[NSLayoutConstraint constraintWithItem:view
                             attribute:NSLayoutAttributeCenterX
                             relatedBy:NSLayoutRelationEqual
                                toItem:view.superview
                             attribute:NSLayoutAttributeCenterX
                            multiplier:1.f constant:0.f];

Можна було б подумати, що ви просто зможете це зробити (це те, що я спочатку думав і намагався, коли побачив це питання):

[NSLayoutConstraint constraintsWithVisualFormat:@"|-(>=20)-[view(==200)]-(>=20)-|"
                                 options: NSLayoutFormatAlignAllCenterX | NSLayoutFormatAlignAllCenterY
                                 metrics:nil
                                   views:@{@"view" : view}];

Я спробував багато різних варіантів вище, намагаючись зігнути його за своїм бажанням, але, схоже, це не стосується нагляду, навіть коли явно є дві окремі рядки VFL для обох осей ( H:|V:). Потім я почав намагатися ізолювати саме тоді, коли параметри будуть застосовані до VFL. Здається, вони не застосовуються до нагляду у VFL і застосовуватимуться лише до явних поглядів, які згадуються у рядку VFL (що в деяких випадках невтішно).

Я сподіваюся, що в майбутньому Apple додасть якусь нову опцію, щоб параметри VFL враховували нагляд, навіть якщо це робиться лише тоді, коли окрім нагляду в VFL є лише один явний вигляд. Іншим рішенням може бути інший варіант прийнятий в VFL , що говорить що - щось на кшталт: NSLayoutFormatOptionIncludeSuperview.

Потрібно сказати, що я багато дізнався про VFL, намагаючись відповісти на це питання.


2
Дякую за детальну відповідь. Єдиною причиною для мене використання VFL є позбавлення від цих потворних шматочків обмежень. Шкода, що Apple цього ще не підтримує ...
Крістіан Шнорр

@larsacus Не могли б ви прокоментувати, чому відповідь нижче працює? Це мене наткнуло.
Метт Г

8
Відповідь Євгена нижче працює, тому що двигун авторозподілу розглядає |і [superview]як окремі внутрішні сутності, хоча вони представляють один і той же смисловий об'єкт. Використовуючи [superview], авторозподіл включає включення об'єкта супервізії у його метрику вирівнювання (у випадку, коли він відповідає у посиланні github, його NSLayoutFormatAlignAllCenterY/ Xmetric).
larsacus

@larsacus Чудовий, спасибі!
Метт Г

Чи знаємо ми, чи обмеження все ще застосовується до версії VFL, яка постачається з поточним iOS 7.x?
Друкс

138

Так, можна зосереджувати перегляд у його огляді за допомогою мови візуального формату. Як вертикально, так і горизонтально. Ось демонстрація:

https://github.com/evgenyneu/center-vfl


15
Це дивовижно, на вашу думку, ви могли б розширити це та пояснити, чому це працює?
тапі

3
Я в кінцевому підсумку використав щось ближче до позначеної відповіді, але +1 для вкладення github у вашому
Рембрандт Q. Ейнштейн

4
@Dan Якщо це не працює для вас, вам може знадобитися обмеження для ширини та висоти. VFL буде таким для ширини: @ "[label (== 200)]" і подібний до висоти: @ "V: [label (== 200)]"
Джонатан Жан

1
Чому результати | і [нагляд] різні? Це щось, що має бути радіолокаційним, чи це відбувається, що я просто не слідкую?
Метт Г

3
Неможливо проаналізувати формат обмежень: параметри маскують необхідні види, щоб вирівняти по горизонтальному краю, що не дозволено для макета, який також горизонтальний. Н: [нагляд] - (<= 1) - [label1]
грабнер

82

Я думаю, що краще створити обмеження вручну.

[superview addConstraint:
 [NSLayoutConstraint constraintWithItem:view
                              attribute:NSLayoutAttributeCenterX
                              relatedBy:NSLayoutRelationEqual
                                 toItem:superview
                              attribute:NSLayoutAttributeCenterX
                             multiplier:1
                               constant:0]];
[superview addConstraint:
 [NSLayoutConstraint constraintWithItem:view
                              attribute:NSLayoutAttributeCenterY
                              relatedBy:NSLayoutRelationEqual
                                 toItem:superview
                              attribute:NSLayoutAttributeCenterY
                             multiplier:1
                               constant:0]];

Тепер ми можемо використовувати NSLayoutAnchor для програмного визначення AutoLayout:

(Доступно в iOS 9.0 та новіших версіях)

view.centerXAnchor.constraint(equalTo: superview.centerXAnchor).isActive = true
view.centerYAnchor.constraint(equalTo: superview.centerYAnchor).isActive = true

Я рекомендую використовувати SnapKit , який є DSL, щоб зробити автоматичну розкладку як на iOS, так і на macOS.

view.snp.makeConstraints({ $0.center.equalToSuperview() })

1
Працював найкраще в моєму контексті - хоча VFL немає.
мозковий масив

це дає мені попередження:Warning once only: Detected a case where constraints ambiguously suggest a height of zero for a tableview cell's content view. We're considering the collapse unintentional and using standard height instead.
Tapas Pal

10

Абсолютно можливо вдалося це зробити так:

[NSLayoutConstraint constraintsWithVisualFormat:@"H:[view]-(<=1)-[subview]"
                                        options:NSLayoutFormatAlignAllCenterY
                                        metrics:nil
                                          views:NSDictionaryOfVariableBindings(view, subview)];

Дізналися про це звідси. Код, що перерахований вище, зосереджується на підгляді Y.

Swift3:

        NSLayoutConstraint.constraints(withVisualFormat: "H:[view]-(<=1)-[subview]",
                                       options: .alignAllCenterY,
                                                       metrics: nil,
                                                       views: ["view":self, "subview":_spinnerView])

7

Додайте код нижче та натисніть кнопку в центрі екрана. Абсолютно можливо.

[self.view addConstraints:[NSLayoutConstraint
                           constraintsWithVisualFormat:@"H:|-[button]-|"
                           options:NSLayoutFormatAlignAllCenterY
                           metrics:0
                           views:views]];

[self.view addConstraints:[NSLayoutConstraint
                           constraintsWithVisualFormat:@"V:|-[button]-|"
                           options:NSLayoutFormatAlignAllCenterX
                           metrics:0
                           views:views]];

1

Я знаю, що це не так, як хочеться, але ви, звичайно, можете обчислити поля і використовувати їх для створення рядка візуального формату;)

У всякому разі, ні. На жаль, це неможливо зробити "автоматично" з VFL - принаймні, поки що.


Ну, ви можете використовувати NSString stringWithFormat: щоб будувати свій рядок VFL динамічно під час виконання.
TRVD1707

1

Завдяки відповіді від @Evgenii, я створюю повний приклад у суті:

центруйте червоний квадрат вертикально з власною висотою

https://gist.github.com/yallenh/9fc2104b719742ae51384ed95dcaf626

Ви можете зосереджувати погляд вертикально, використовуючи VFL (що не зовсім інтуїтивно) або використовувати обмеження вручну. До речі, я не можу поєднувати як центрY, так і висоту разом у VFL:

"H:[subView]-(<=1)-[followIcon(==customHeight)]"

У поточному рішенні обмеження VFL додаються окремо.


0

Що потрібно зробити, це те, що в словнику повинен бути оголошений нагляд. Замість використання |ви використовуєте @{@"super": view.superview};.

І NSLayoutFormatAlignAllCenterXдля вертикальних, і NSLayoutFormatAlignAllCenterYдля горизонтальних як варіантів.


0

Ви можете використовувати додаткові представлення даних.

NSDictionary *formats =
@{
  @"H:|[centerXView]|": @0,
  @"V:|[centerYView]|": @0,
  @"H:[centerYView(0)]-(>=0)-[yourView]": @(NSLayoutFormatAlignAllCenterY),
  @"V:[centerXView(0)]-(>=0)-[yourView]": @(NSLayoutFormatAlignAllCenterX),
};
NSDictionary *views = @{
  @"centerXView": centerXView, 
  @"centerYView": centerYView, 
  @"yourView": yourView,
};
 ^(NSString *format, NSNumber *options, BOOL *stop) {
     [superview addConstraints:
      [NSLayoutConstraint constraintsWithVisualFormat:format
                                              options:options.integerValue
                                              metrics:nil
                                                views:views]];
 }];

Якщо ви хочете, щоб це було акуратно, то centerXView.hidden = centerYView.hidden = YES;.

PS: Я не впевнений, що я можу назвати додаткові погляди "заповнювачами", оскільки англійська мова - це моя друга мова. Буде вдячно, якщо хтось може мені це сказати.


Щось тут не вистачає. Як ви називаєте блок під декларацією переглядів ? Це не юридичний кодекс, як ви його
виклали

0

Для тих, хто прийшов сюди за Interface Builderрішенням (Google веде мене сюди), просто додайте обмеження на ширину / висоту const та виберіть підпогляд -> перетягування керування для його нагляду -> виберіть "центр вертикально / горизонтально в огляді".


0

Це мій метод

//create a 100*100 rect in the center of superView
var consts = NSLayoutConstraint.constraints(withVisualFormat: "H:|-space-[myView]-space-|", options: [], metrics:["space":view.bounds.width/2-50], views:["myView":myView])

consts += NSLayoutConstraint.constraints(withVisualFormat: "V:|-space-[myView]-space-|", options: [], metrics: ["space":view.bounds.height/2-50], views: ["myView":myView])

-1

Просто потрібно сказати, що ви можете використовувати це замість обмежень:

child.center = [parent convertPoint:parent.center fromView:parent.superview];

4
Потрібно лише сказати, що це не те, про що він просить, і це не спрацює, якщо ви повернете пристрій,
зміните

-1

@ igor-muzyka відповідь у Swift 2 :

NSLayoutConstraint.constraintsWithVisualFormat("H:[view]-(<=1)-[subview]", 
                                               options: .AlignAllCenterY,
                                               metrics: nil,
                                               views: ["view":view, "subview":subview])

-3

Замість використання VFL ви можете легко зробити це в конструкторі інтерфейсів. На головному аркуші розгортання клавіш ctrl + клацніть на представленні, яке ви хочете відцентрувати. Перетягніть до перегляду (утримуючи клавішу ctrl) і виберіть "Центр X" або "Центр Y". Код не потрібен.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.