Подтвердить что ты не робот

Центрирование с визуальным форматом NSLayoutConstraints

Я пытаюсь центрировать представление, используя язык визуального формата.

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

(views является NSDictionaryOfVariableBindings, содержащим _progressView)

Он не центрирует мой вид (ширина: 300) в пределах self.view (ширина: 768). Он выравнивает его налево с краем 8 пикселей, как будто я бы написал только @"H:|-[_progressView(300)".

Это единственный способ сосредоточить взгляд, используя что-то вроде:?

[self.view addConstraint:[NSLayoutConstraint constraintWithItem:_progressView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual
                                                             toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1 constant:0]];

Спасибо

4b9b3361

Ответ 1

Эта строка формата

@"H:|-[_progressView(300)]-|"

не указывает AutoLayout в центр progressView. Вместо этого он говорит, что progressView должен быть шириной 300 и иметь системную границу с обеих сторон к краям супервизора. Очевидно, это не может быть выполнено, поэтому Auto Layout снижает некоторые ограничения (вы, вероятно, получаете несколько журналов на консоли). Ограничение, которое выпадает в вашем случае, вероятно, является полем справа.

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

@interface UIView (MyLayout)
- (void)centerHorizontallyInSuperview;
@end

@implementation UIView (MyLayout)
- (void)centerHorizontallyInSuperview {
    NSLayoutConstraint *c;
    c = [NSLayoutConstraint constraintWithItem:self
                                     attribute:NSLayoutAttributeCenterX
                                     relatedBy:NSLayoutRelationEqual                                                             
                                        toItem:self.superview
                                     attribute:NSLayoutAttributeCenterX 
                                    multiplier:1 
                                      constant:0];
    [self.superview addConstraint:c];
}
@end

Ответ 2

Три подхода:

  • Вы можете поместить свое ограничение на добавление кода в метод или категорию, как это было предложено DrummerB.

    Вы также, эффективный iOS 9, можете использовать более новый, более сжатый синтаксис, используя анкеры и используя activateConstraints:

    [NSLayoutConstraint activateConstraints:@[
        [centerView.centerXAnchor constraintEqualToAnchor:view.centerXAnchor],
        ...
    ]];
    

    Или в Swift 3:

    NSLayoutConstraint.activate([
        centerView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
        ...
    ])
    
  • Вы можете использовать объекты UILayoutGuide:

    UILayoutGuide *leftGuide = [[UILayoutGuide alloc] init];
    [view addLayoutGuide:leftGuide];
    UILayoutGuide *rightGuide = [[UILayoutGuide alloc] init];
    [view addLayoutGuide:rightGuide];
    

    и определите их равными друг другу с помощью VFL следующим образом:

    H:|[leftGuide][_progressView(==300)][rightGuide(==leftGuide)]|
    

    Если вы не можете использовать руководства по макетам (например, вам нужно поддерживать версии iOS до 9.0, вы хотите создать их в IB и т.д.), вы можете использовать невидимые объекты UIView (альфа нулевого или фона цвет прозрачного) очень похожим образом. Просто добавьте эти "spacer" виды в свою иерархию представлений, используйте горизонтальные ограничения, как указано выше, но просто настройте представления, чтобы их не было видно.

    Этот метод был бы громоздким способом решения проблемы "как сделать задачу центра", но чрезвычайно полезен, если вы, например, хотите равномерно разместить дюжину просмотров, и вы не можете использовать UIStackView по какой-то причине. Вы можете использовать любые UILayoutGuide (или невидимые UIView) объекты, которые вы хотите, чтобы достичь желаемого эффекта.

  • Для полноты я должен указать, что можно добиться эффекта, используя options of NSLayoutFormatAlignAllCenterX/Y, как указано в fooobar.com/questions/41665/..., но я признаюсь, что считаю это излишне запутанным.

Лично я считаю, что первый подход имеет наибольший смысл для вашего сценария. Второй подход полезен при попытке равномерного размещения множества элементов управления, но слишком неуклюж для этого простого сценария. Третий подход - это интеллектуальное любопытство, но я бы не предложил его ни в каком реальном приложении.

Ответ 3

Для тех, кто в ней нуждается, @DrummerB ObjC категория как расширение Swift:

extension UIView {

    func centerInSuperview() {
        self.centerHorizontallyInSuperview()
        self.centerVerticallyInSuperview()
    }

    func centerHorizontallyInSuperview(){
        let c: NSLayoutConstraint = NSLayoutConstraint(item: self, attribute: .CenterX, relatedBy: .Equal, toItem: self.superview, attribute: .CenterX, multiplier: 1, constant: 0)
        self.superview?.addConstraint(c)
    }

    func centerVerticallyInSuperview(){
        let c: NSLayoutConstraint = NSLayoutConstraint(item: self, attribute: .CenterY, relatedBy: .Equal, toItem: self.superview, attribute: .CenterY, multiplier: 1, constant: 0)
        self.superview?.addConstraint(c)
    }

}