Центрирование представления в своем супервизоре с использованием языка Visual Format

Я только начал изучать AutoLayout для iOS и посмотрел на язык Visual Format.

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

Ответ 1

В настоящее время нет, это не похоже на то, что можно центрировать представление в супервизии, используя только 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

Да, можно сосредоточить представление в своем супервизоре с помощью языка Visual Format. Вертикально и горизонтально. Вот демо:

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

Ответ 3

Я думаю, что лучше вручную создавать ограничения.

[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() })

Ответ 4

Абсолютно возможно удалось сделать это вот так:

[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])

Ответ 5

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

[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]];

Ответ 6

Я знаю, что вы этого не хотите, но вы можете, конечно, рассчитать поля и использовать их для создания строки визуального формата;)

В любом случае, нет. К сожалению, это невозможно сделать "автоматически" с VFL - по крайней мере, пока.

Ответ 7

Благодаря ответу от @Evgenii, я создаю полный пример в gist:

центрировать красный квадрат по вертикали с пользовательской высотой

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

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

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

В текущем решении ограничения VFL добавляются отдельно.

Ответ 8

Что нужно сделать, так это то, что супервизор должен быть объявлен в словаре. Вместо использования | вы используете @{@"super": view.superview};.

И NSLayoutFormatAlignAllCenterX для вертикального и NSLayoutFormatAlignAllCenterY для горизонтальных в качестве параметров.

Ответ 9

Вы можете использовать дополнительные виды.

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: Я не уверен, что могу назвать дополнительные представления "заполнителями", потому что английский - это мой второй язык. Будет оценено, если кто-то скажет мне это.

Ответ 10

Для тех, кто пришел сюда для решения Interface Builder (Google приводит меня сюда), просто добавьте ограничения ширины/высоты const и выберите subview → control drag to this superview → выберите "center vertical/horizontally in SuperView".

Ответ 11

@igor-muzyka ответ в Swift:

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

Ответ 12

Просто нужно сказать, что u может использовать это вместо ограничений:

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

Ответ 13

Вместо использования VFL вы можете легко сделать это в построителе интерфейса. В Главной раскадровке нажмите Ctrl + клик по виду, которое хотите центрировать. Перетащите в супервизор (удерживая Ctrl) и выберите "Центр X" или "Центр Y". Не требуется код.