Центрирование представления в его суперпредставлении с использованием Visual Format Language
Я только начал изучать AutoLayout для iOS и взглянул на Visual Format Language.
Все работает отлично, за исключением одного: я просто не могу получить представление в центре его суперпредставления.
Возможно ли это с VFL или мне нужно вручную создать ограничение?
13 ответов
В настоящее время нет, не похоже, что можно центрировать вид в суперпредставлении, используя только 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, пытаясь ответить на этот вопрос.
Да, можно центрировать представление в его суперпредставлении с помощью языка визуальных форматов. Как вертикально, так и горизонтально. Вот демо:
Я думаю, что лучше вручную создавать ограничения.
[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, чтобы упростить Auto Layout на iOS и MacOS.
view.snp.makeConstraints({ $0.center.equalToSuperview() })
Абсолютно возможно было сделать это так:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:[view]-(<=1)-[subview]"
options:NSLayoutFormatAlignAllCenterY
metrics:nil
views:NSDictionaryOfVariableBindings(view, subview)];
Узнал это отсюда. Код выше центрирует subview с точки зрения Y, очевидно.
Swift3:
NSLayoutConstraint.constraints(withVisualFormat: "H:[view]-(<=1)-[subview]",
options: .alignAllCenterY,
metrics: nil,
views: ["view":self, "subview":_spinnerView])
Добавьте приведенный ниже код и поместите свою кнопку в центр экрана. Абсолютно возможно.
[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]];
Благодаря ответу @Evgenii я создаю полный пример в gist:
отцентрируйте красный квадрат вертикально по высоте
https://gist.github.com/yallenh/9fc2104b719742ae51384ed95dcaf626
Вы можете центрировать представление по вертикали, используя VFL (что не совсем интуитивно понятно) или используя ограничения вручную. Кстати, я не могу объединить центр и высоту вместе в VFL, как:
"H:[subView]-(<=1)-[followIcon(==customHeight)]"
В текущем решении ограничения VFL добавляются отдельно.
Я знаю, что вы этого не хотите, но вы, конечно, можете рассчитать поля и использовать их для создания строки визуального формата;)
Во всяком случае нет. К сожалению, это невозможно сделать "автоматически" с VFL - по крайней мере, пока.
Вы можете использовать дополнительные виды.
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: я не уверен, что могу назвать дополнительные представления "заполнителями", потому что английский - мой второй язык. Будет оценено, если кто-то скажет мне это.
@igor-muzyka ответ в Swift 2:
NSLayoutConstraint.constraintsWithVisualFormat("H:[view]-(<=1)-[subview]",
options: .AlignAllCenterY,
metrics: nil,
views: ["view":view, "subview":subview])
Для тех, кто пришел сюда за Interface Builder
на основе решения (Google приводит меня сюда), просто добавьте постоянные ограничения ширины / высоты и выберите подпредставление -> элемент управления перетаскиванием в его суперпредставление -> выберите "центр вертикально / горизонтально в суперпредставлении".
Что нужно сделать, так это то, что суперпредставление должно быть объявлено в словаре. Вместо того, чтобы использовать |
ты используешь @{@"super": view.superview};
,
А также NSLayoutFormatAlignAllCenterX
для вертикальных и NSLayoutFormatAlignAllCenterY
для горизонтальных опций.
Это мой метод
//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])
Просто нужно сказать, что вы можете использовать это вместо ограничений:
child.center = [parent convertPoint:parent.center fromView:parent.superview];
Вместо использования VFL вы можете легко сделать это в конструкторе интерфейсов. На главной раскадровке Ctrl+ клик по представлению, которое вы хотите центрировать. Перетащите на суперпредставление (удерживая Ctrl) и выберите "Центр X" или "Центр Y". Код не нужен.