Visual Format Languageを使用してビューをスーパービューの中央に配置する


160

私はAutoLayout for iOSの学習を始めたばかりで、Visual Format Languageを調べました。

1つを除いて、すべて正常に機能します。スーパービューの中心にビューを配置できません。
これは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}];

上記のさまざまなバリエーションを試してみましたが、両方の軸に2つの別々のVFL文字列を明示的に持っていても(H:|V:)、スーパービューには適用されないようです。次に、オプション VFLに適用されるタイミングを正確に切り分けようとしました。彼らはように見えない VFLにスーパービューに適用され、唯一の(一定の場合には残念です)VFL列に記載されている明示的なビューに適用されます。

VFLのスーパービューに加えて明示的なビューが1つしかない場合にのみ、VFLオプションがスーパービューを考慮するようにするために、Appleが将来的に何らかの新しいオプションを追加することを願っています。別の解決策としては、VFLに渡される別のオプションが考えられますNSLayoutFormatOptionIncludeSuperview

言うまでもなく、私はこの質問に答えようとするVFLについて多くを学びました。


2
詳しい回答ありがとうございます。ただし、VFLを使用する唯一の理由は、これらの醜い束の制約を取り除くことです。Appleはこれをまだサポートしていません...
Christian Schnorr 2012年

@larsacus以下の答えが機能する理由についてコメントしていただけますか?私は困惑しています。
マットG

8
以下のEvgenyの回答は、オートレイアウトエンジンが同じセマンティックオブジェクトを表す場合でも、独立した内部エンティティとして扱い|、処理するため有効[superview]です。[superview]autolayout を使用することにより、スーパービューオブジェクトがその配置メトリックに含まれます(githubリンクでの彼の回答の場合、そのNSLayoutFormatAlignAllCenterY/ Xメトリック)。
larsacus 14

@larsacus素晴らしい、ありがとう!
マットG

現在のiOS 7.xに同梱されているVFLのバージョンにも制限が適用されるかどうかはわかりますか?
Drux、2014年

138

はい、Visual Format Languageを使用して、スーパービューのビューを中央に配置することができます。垂直方向と水平方向の両方。ここにデモがあります:

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


15
これはすばらしいです。これを拡張して、なぜ機能するかを説明できますか?
Tapi

3
私はマークされた答えに近いものを利用することになりましたが、あなたのgithubアタッチメントに+1しました
レンブラントQ.アインシュタイン

4
@Danうまくいかない場合は、幅と高さにも制約を設ける必要があるかもしれません。VFLは幅の場合は次のようになります:@ "[label(== 200)]"高さの場合は次のようになります:@ "V:[label(== 200)]"
Jonathan Zhan

1
なぜからの結果ですか?と[スーパービュー]が違う?これはレーダーで処理すべきものですか、それとも私がフォローしていないだけですか?
Matt G

3
制約フォーマットを解析できません:オプションはビューを水平エッジに揃える必要があるビューをマスクします。これは水平でもあるレイアウトでは許可されません H:[superview]-(<= 1)-[label1]
グラバー、2014年

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を使用することをお勧めします。これは、iOSとmacOSの両方で自動レイアウトを容易にするDSLです。

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

1
私のコンテキストで最もよく機能しました-VFLはありません。
ブレインレイ2014年

警告が表示されます: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(非常に直感的ではありません)を使用するか、手動で制約を使用して、ビューを垂直方向に中央揃えにすることができます。ちなみに、私はcenterYと高さの両方をVFLで一緒に組み合わせることはできません:

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

現在のソリューションでは、VFL制約が個別に追加されています。


0

スーパービューは辞書で宣言する必要があるということです。を使用|する代わりに、を使用します@{@"super": view.superview};

またNSLayoutFormatAlignAllCenterXNSLayoutFormatAlignAllCenterYオプションとして、垂直方向と水平方向にも使用できます。


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
言う必要があるだけです、それは彼が求めていることではなく、デバイスを回転させたり、画面のサイズを変更したりしても機能しません
jeffjv

-1

Swift 2での@ igor-muzykaの回答:

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

-3

VFLを使用する代わりに、インターフェースビルダーでこれを簡単に行うことができます。メインストーリーボードで、中央揃えにするビューをCtrlキーを押しながらクリックします。スーパービューにドラッグし(Ctrlキーを押しながら)、[中央X]または[中央Y]を選択します。コードは必要ありません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.