web-dev-qa-db-ja.com

自動レイアウトを使用して、横向きと縦向きに異なる制約を提供できますか?

デバイスを回転させたときに制約を変更することはできますか?これはどのように達成できますか?

簡単な例としては、2つの画像を縦向きに重ね、横向きに並べる場合があります。

これが不可能な場合、このレイアウトを他にどのように達成できますか?

インターフェイスビルダーを使用せずに、コードでビューと制約を構築しています。

47
Ben Packard

編集:Size Classes の新しいコンセプトを使用してXcode 6で導入、Interface Builderで特定のサイズクラスにさまざまな制約を簡単に設定できます。ほとんどのデバイス(たとえば、現在のすべてのiPhone)には、横向きモードでCompact垂直サイズクラスがあります。

これは、デバイスの向きを決定するよりも、一般的なレイアウト決定にとってはるかに優れた概念です。

そうは言っても、本当に方向を知る必要がある場合は、UIDevice.currentDevice().orientationが道です。


元の投稿:

updateViewConstraintsUIViewControllerメソッドをオーバーライドして、特定の状況にレイアウト制約を提供します。このように、レイアウトは常に状況に応じて正しい方法で設定されます。ストーリーボード内で作成された制約と完全な制約を形成していることを確認してください。 IBを使用して、一般的な制約を設定し、実行時に削除されるように変更の対象としてマークすることができます。

次の実装を使用して、方向ごとに異なる制約セットを提示します。

-(void)updateViewConstraints {
    [super updateViewConstraints];

    // constraints for portrait orientation
    // use a property to change a constraint's constant and/or create constraints programmatically, e.g.:
    if (!self.layoutConstraintsPortrait) {
        UIView *image1 = self.image1;
        UIView *image2 = self.image2;
        self.layoutConstraintsPortrait = [[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[image1]-[image2]-|" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(image1, image2)] mutableCopy];
        [self.layoutConstraintsPortrait addObject:[NSLayoutConstraint constraintWithItem:image1 attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem: image1.superview attribute:NSLayoutAttributeCenterY multiplier:1 constant:0]];
        [self.layoutConstraintsPortrait addObject:[NSLayoutConstraint constraintWithItem:image2 attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:image2.superview attribute:NSLayoutAttributeCenterY multiplier:1 constant:0]];
    }

    // constraints for landscape orientation
    // make sure they don't conflict with and complement the existing constraints
    if (!self.layoutConstraintsLandscape) {
        UIView *image1 = self.image1;
        UIView *image2 = self.image2;
        self.layoutConstraintsLandscape = [[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[image1]-[image2]-|" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(image1, image2)] mutableCopy];
        [self.layoutConstraintsLandscape addObject:[NSLayoutConstraint constraintWithItem:image1 attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:image1.superview attribute:NSLayoutAttributeCenterY multiplier:1 constant:0]];
        [self.layoutConstraintsLandscape addObject:[NSLayoutConstraint constraintWithItem:image2 attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem: image2.superview attribute:NSLayoutAttributeCenterY multiplier:1 constant:0]];
    }

    BOOL isPortrait = UIInterfaceOrientationIsPortrait(self.interfaceOrientation);
    [self.view removeConstraints:isPortrait ? self.layoutConstraintsLandscape : self.layoutConstraintsPortrait];
    [self.view addConstraints:isPortrait ? self.layoutConstraintsPortrait : self.layoutConstraintsLandscape];        
}

これで、必要なのは、状況が変化するたびに制約の更新をトリガーすることだけです。オーバーライドwillAnimateRotationToInterfaceOrientation:duration:向きの変更に関する制約の更新をアニメーション化するには:

- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
    [super willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration];

    [self.view setNeedsUpdateConstraints];

}
39
knl

私が使用しているアプローチ(良くも悪くも)は、ストーリーボードエディタで両方の制約(ポートレートとランドスケープ)を定義することです。

地獄の絵コンテの警告を避けるために、1つのセットをすべて999の優先度に設定します。

次に、すべての制約をアウトレットコレクションに追加します。

@property (strong, nonatomic) IBOutletCollection(NSLayoutConstraint) NSArray *portraitConstraints;
@property (strong, nonatomic) IBOutletCollection(NSLayoutConstraint) NSArray *landscapeConstraints;

最後に、ViewControllersviewWillLayoutメソッドを実装します。

- (void) viewWillLayoutSubviews {
    [super viewWillLayoutSubviews];
    for (NSLayoutConstraint *constraint in self.portraitConstraints) {
        constraint.active = (UIApplication.sharedApplication.statusBarOrientation == UIDeviceOrientationPortrait);
    }
    for (NSLayoutConstraint *constraint in self.landscapeConstraints) {
        constraint.active = (UIApplication.sharedApplication.statusBarOrientation != UIDeviceOrientationPortrait);
    }
}

これはうまくいくようです。 I 本当にストーリーボードエディタでデフォルトのアクティブなプロパティを設定できるといいのに。

17
Travis Griggs

私はあなたと同じアプローチに従っています(nibファイルやストーリーボードはありません)。 updateViewConstraintsメソッドで制約を更新する必要があります(デバイスの向きを確認して)。デバイスの向きを変更するとすぐに最後のメソッドが自動的に呼び出されるため、setNeedsUpdateConstraintsupdateViewConstraintsを呼び出す必要はありません。

2
rokridi

制約をプロパティまたは変数にポートレートおよびランドスケープバージョンとして保存し、回転時に設定および削除できます。

これを行って、初期ビューのxibで制約を作成し、View Controllerのアウトレットに割り当てました。回転時に、代替の拘束を作成し、アウトレットを削除しますが、それらを保持し、代替を挿入します。

逆回転でプロセスを逆にします。

0
Dean Davids