web-dev-qa-db-ja.com

プログラムでレイアウト制約を作成する

私は多くの人がすでにこれについて多くの質問をしていることを知っていますが、答えがあってもそれを機能させることはできません。

ストーリーボードの制約を扱うときは簡単ですが、コードでは苦労します。たとえば、右側に表示を維持し、画面の向きに応じて画面の高さを表示するようにします。これは私のコードです:

UIView *myView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200, 748)];
myView.backgroundColor = [UIColor redColor];
[self.view addSubview:myView];
[self.view addConstraints:[NSLayoutConstraint
    constraintsWithVisualFormat:@"V:|-[myView(>=748)]-|"
    options:0 metrics:nil
    views:NSDictionaryOfVariableBindings(myView)]];

いくつかの制約を満たしていません。何が悪いのかわかりません。また、なぜmyViewのようなローカル変数の代わりにself.myViewのようなプロパティを使用できないのですか?

84
pierre23

コードで自動レイアウトを使用する場合、フレームを設定しても何も起こりません。したがって、上のビューで幅200を指定したという事実は、それに制約を設定するときに何の意味もありません。ビューの制約セットを明確にするためには、特定の状態のx位置、y位置、幅、高さの4つのものが必要です。

現在、上記のコードには2つしかありません(高さ、スーパービューに対する相対的な位置、およびy位置、スーパービューに対する相対的な位置)。これに加えて、ビューのスーパービューの制約の設定方法に応じて競合する可能性のある2つの必須制約があります。 スーパービューに、高さが748未満の値であることを指定する必要な制約がある場合、「満たされない制約」例外が発生します。

制約を設定する前にビューの幅を設定したという事実は何も意味しません。古いフレームも考慮せず、それらのビューに指定したすべての制約に基づいて新しいフレームを計算します。コードで自動レイアウトを扱う場合、通常はinitWithFrame:CGRectZeroまたは単にinitを使用して新しいビューを作成します。

質問で口頭で説明したレイアウトに必要な制約セットを作成するには、完全に指定されたレイアウトを提供するために、幅とx位置を区切るためにいくつかの水平制約を追加する必要があります。

[self.view addConstraints:[NSLayoutConstraint
    constraintsWithVisualFormat:@"V:|-[myView(>=748)]-|"
    options:NSLayoutFormatDirectionLeadingToTrailing
    metrics:nil
    views:NSDictionaryOfVariableBindings(myView)]];

[self.view addConstraints:[NSLayoutConstraint
    constraintsWithVisualFormat:@"H:[myView(==200)]-|"
    options:NSLayoutFormatDirectionLeadingToTrailing
    metrics:nil
    views:NSDictionaryOfVariableBindings(myView)]];

このレイアウトを口頭で説明すると、垂直方向の制約から次のようになります。

myViewは、そのスーパービューの高さを標準スペースに等しい上下のパディングで埋めます。 myViewのスーパービューの最小の高さは748ptsです。 myViewの幅は200ptsで、スーパービューに対して標準のスペースに等しい右側のパディングがあります。

スーパービューの高さを制限せずにビューがスーパービュー全体の高さだけを満たすようにしたい場合は、視覚形式テキストの(>=748)パラメーターを省略します。 (>=748)パラメーターが高さを与えるために必要だと思われる場合-この場合、バー(|)またはスペースのあるバー(|--|)構文を使用してスーパービューの端にビューを固定しないでください。ビューのy位置(シングルエッジでのビューの固定)、および高さを持つy位置(両方のエッジでのビューの固定)により、ビューの制約セットを満たします。

2番目の質問に関して:

NSDictionaryOfVariableBindings(self.myView)を使用して(myViewのプロパティが設定されている場合)、VFLテキストにself.myViewを使用するためにそれをVFLにフィードすると、おそらくautolayoutがVFLテキストを解析しようとすると例外が発生します。辞書キーのドット表記と、valueForKeyPath:を使用しようとするシステムに関係しています。 同様の質問と回答はこちらをご覧ください

106
larsacus

こんにちは、私はこのページを多くの制約と「方法」に使用しています。必要なことに気付くまでに永遠にかかりました。

myView.translatesAutoresizingMaskIntoConstraints = NO;

この例を機能させるには。 Userxxx、Rob M.、特にここの説明とコードについてlarsacusに感謝します。非常に貴重です。

上記の例を実行するための完全なコードは次のとおりです。

UIView *myView = [[UIView alloc] init];
myView.backgroundColor = [UIColor redColor];
myView.translatesAutoresizingMaskIntoConstraints = NO;  //This part hung me up 
[self.view addSubview:myView];
//needed to make smaller for iPhone 4 dev here, so >=200 instead of 748
[self.view addConstraints:[NSLayoutConstraint
                           constraintsWithVisualFormat:@"V:|-[myView(>=200)]-|"
                           options:NSLayoutFormatDirectionLeadingToTrailing
                           metrics:nil
                           views:NSDictionaryOfVariableBindings(myView)]];

[self.view addConstraints:[NSLayoutConstraint
                           constraintsWithVisualFormat:@"H:[myView(==200)]-|"
                           options:NSLayoutFormatDirectionLeadingToTrailing
                           metrics:nil
                           views:NSDictionaryOfVariableBindings(myView)]];
61
BriOnH

迅速なバージョン

Swift 3に更新

この例では、Interface Builderで行う場合と同じように、次の制約をプログラムで追加する2つの方法を示します。

幅と高さ

enter image description here

コンテナの中心

enter image description here

定型コード

override func viewDidLoad() {
    super.viewDidLoad()

    // set up the view
    let myView = UIView()
    myView.backgroundColor = UIColor.blue
    myView.translatesAutoresizingMaskIntoConstraints = false
    view.addSubview(myView)

    // Add constraints code here (choose one of the methods below)
    // ...
}

方法1:アンカースタイル

// width and height
myView.widthAnchor.constraint(equalToConstant: 200).isActive = true
myView.heightAnchor.constraint(equalToConstant: 100).isActive = true

// center in container
myView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
myView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true

方法2:NSLayoutConstraintスタイル

// width and height
NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.width, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: 200).isActive = true
NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.height, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: 100).isActive = true

// center in container
NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.centerX, relatedBy: NSLayoutRelation.equal, toItem: view, attribute: NSLayoutAttribute.centerX, multiplier: 1, constant: 0).isActive = true
NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.centerY, relatedBy: NSLayoutRelation.equal, toItem: view, attribute: NSLayoutAttribute.centerY, multiplier: 1, constant: 0).isActive = true

ノート

  • アンカースタイルはNSLayoutConstraintスタイルよりも望ましい方法ですが、iOS 9からのみ使用できるため、iOS 8をサポートしている場合は、NSLayoutConstraintスタイルを引き続き使用する必要があります。
  • Programmatically Creating Constraints documentationも参照してください。
  • ピン留め制約を追加する同様の例については、 この回答 を参照してください。
10
Suragch

プロパティに関する2番目の質問については、クラスでプロパティとして宣言した場合にのみself.myViewを使用できます。 myViewはローカル変数であるため、そのように使用することはできません。この詳細については、 宣言されたプロパティ のAppleドキュメントを参照することをお勧めします。

5
iDev

myViewのようなローカル変数の代わりにself.myViewのようなプロパティを使用できないのはなぜですか?

使用してみてください:

NSDictionaryOfVariableBindings(_view)

self.viewの代わりに

5
Megarushing

IOS9から、新しいヘルパークラス NSLayoutAnchor のサブクラスを使用して、制約をプログラムで「より簡潔で読みやすい」に定義できることに注意してください。

ドキュメントの例:

[self.cancelButton.leadingAnchor constraintEqualToAnchor:self.saveButton.trailingAnchor constant: 8.0].active = true;
4
andreacipriani