web-dev-qa-db-ja.com

視覚フォーマットNSLayoutConstraintsを使用したビューの中央揃え

視覚フォーマット言語を使用してビューを中央に配置しようとしています。

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

viewsは__progressView_を含むNSDictionaryOfVariableBindingsです)

ビュー(幅:300)を_self.view_(幅:768)の中央に配置しません。 @"H:|-[_progressView(300)"とだけ書いたかのように、8ピクセルのマージンで左揃えにします。

次のようなものを使用してビューを中央に配置する唯一の方法はありますか?

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

ありがとう

22
Joseph

このフォーマット文字列

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

autoLayoutに中央揃えprogressViewを指示しません。代わりに、progressViewは300の幅であり、システムで定義された標準のマージンがスーパービューの端の両側にある必要があると述べています。明らかにこれは満足できないので、自動レイアウトはいくつかの制約を落とします(おそらくコンソールにいくつかのログが表示されます)。あなたのケースで削除された制約は、おそらく右側のマージンです。

ビューをスーパービューの真ん中に配置するには、既に理解しているように、視覚的な文字列形式の代わりに詳細な制約メソッドを使用する必要があります。ただし、次のように簡単にニースのカテゴリに入れることができます。

@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
34
DrummerB

3つのアプローチ:

  1. DrummerBで提案されているように、メソッドまたはカテゴリに制約を追加するコードを配置できます。

    また、効果的なiOS 9では、アンカーを使用し、activateConstraintsを使用して、より新しく、より簡潔な構文を使用できます。

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

    またはSwift 3:

    NSLayoutConstraint.activate([
        centerView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
        ...
    ])
    
  2. UILayoutGuideオブジェクトを使用できます。

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

    次のように、VFLでそれらが互いに等しくなるように定義します。

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

    レイアウトガイドを使用できない場合(たとえば、9.0より前のiOSバージョンをサポートする必要がある場合、これをIBで作成する場合など)、非表示のUIViewオブジェクト(ゼロまたは背景のアルファ)を​​使用できます。クリアの色)と非常によく似ています。これらの「スペーサー」ビューをビュー階層に追加し、上記のような水平方向の制約を使用しますが、ビューが見えないように構成するだけです。

    この手法は、「ビューを中央に配置する方法」の問題を解決する面倒な方法ですが、たとえば、12のビューを均等に配置したい場合にUIStackViewを使用できない場合に非常に役立ちます。何らかの理由で。希望する効果を実現するために、いくつでもUILayoutGuide(または非表示のUIView)オブジェクトを使用できます。

  3. 完全を期すために、私は https:/で概説されているように、options/NSLayoutFormatAlignAllCenterXYを使用して効果を達成することが可能であることを指摘する必要があります/stackoverflow.com/a/14917695/1271826 ですが、不必要に混乱していることを認めます。

個人的には、最初のアプローチがあなたのシナリオにとって最も理にかなっていると思います。 2番目の方法は、多数のコントロールを均等に配置しようとする場合に便利ですが、この単純なシナリオには扱いにくいです。 3番目のアプローチは知的好奇心ですが、実際のアプリケーションでは推奨しません。

17
Rob

それを必要とする人のために、@ 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)
    }

}
7
Koen.