web-dev-qa-db-ja.com

autolayoutを使用して、コンテナビューに一致するように動的UIViewを設定します

コンテナビューとして使用している別のUIViewを含むIBのUIViewがあります。コードでは、3つの異なるビューを作成し、アプリの状態に応じて適切なビューをコンテナのビューにアニメーション化します。常に有効なのは3つの異なるビューのうちの1つだけです。問題は、シミュレーターで別のiPhoneを実行すると、新しいサブビューがコンテナービューに合わせて拡大縮小されないことです。自動レイアウトを使用しています。テストのために、サブビューを、すべてのエッジがスーパービューに制限されている大きなボタンに設定しました。また、コンテナビューのエッジもスーパービューに制限されています。私が望むのは、サブビューがコンテナのビューに一致することです。つまり、ボタンはコンテナビューのサイズ全体を拡大します。異なるiPhoneで実行する場合、コンテナビューのサイズ、したがってサブビューは、異なるiPhoneの画面サイズに比例してスケーリングする必要があります。

以下は、サブビューを初期化し、コンテナビューに関連する制約を設定するために使用するコードです。

UIView *containerView = self.subView;
UIView *newSubview = [[mySubview alloc] init];
[newSubview setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.containerView addSubview:newSubview];

[self.containerView addConstraint:[NSLayoutConstraint constraintWithItem:newSubview attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.containerView attribute:NSLayoutAttributeTop multiplier:1.0 constant:0]];

[self.containerView addConstraint:[NSLayoutConstraint constraintWithItem:newSubview attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.containerView attribute:NSLayoutAttributeLeading multiplier:1.0 constant:0]];

[self.containerView addConstraint:[NSLayoutConstraint constraintWithItem:newSubview attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self.containerView attribute:NSLayoutAttributeWidth multiplier:1.0 constant:0]];

[self.containerView addConstraint:[NSLayoutConstraint constraintWithItem:newSubview attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self.containerView attribute:NSLayoutAttributeHeight multiplier:1.0 constant:0]];  

これを機能させることができないようです。私はオートレイアウトにかなり慣れていないので、自分が何を間違えているかわからないので、この壁に頭をぶつけるのをやめたいです。どんな助けも素晴らしいでしょう。 :)


************* 追加情報 **************


申し訳ありませんが、自分の問題をできるだけ明確に述べていません。そのため、ここにスクリーンショットの詳細を示します。最初に、コード単位で行ったことを説明します。

AppDelegate.mのdidFinishLaunchingWithOptionsで、このようにMyViewControllerを作成し、

self.myViewController = [[MyViewController alloc] initWithNibName:@"MyViewController" bundle:nil];

MyViewController.mのviewDidLoadで、mySubviewを作成してcontainerViewに追加し、次のように制約を作成します。

UIView *containerView = self.containerView;
UIView *mySubview = [[MySubview alloc] init];
[mySubview setTranslatesAutoresizingMaskIntoConstraints:NO];
[containerView addSubview:mySubview];

NSDictionary *views = NSDictionaryOfVariableBindings(mySubview);
[containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[mySubview]|"
                                                                 options:0
                                                                 metrics:nil
                                                                   views:views]];
[containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[mySubview]|"
                                                                  options:0
                                                                  metrics:nil
                                                                    views:views]];

最後に、MySubview.hのinitで、このようなサブビューとしてペン先を追加します。

- (id)init
{
    if(self = [super init])
    {
        NSArray *nibArray = [[NSBundle mainBundle]loadNibNamed:@"MySubview" owner:self options:nil];
        [self addSubview:[nibArray objectAtIndex:0]];
    }
    return self;
}

役立つ可能性のあるいくつかの注意事項、

MyViewController.xibには、containerViewとして使用しているUIViewがあります。 UIView * containerViewへのIBOutletがあり、上記で参照したものです。 IBのcontainerViewに対して私が持っている唯一の制約は、先頭、末尾、下部のスペースからSuperview、上部のスペースからSuperview = 44です。

MySubview.xibの場合、高さと幅は300です(高さまたは幅に制約は使用されません)。 mySubviewはcontainerViewに制約されることになっているため、これらのサイズは重要ではないと感じています。

MySubview.xibには、topButton:height = 29、middleView:height = 242、bottomButton:height = 29の3つのオブジェクトがあります(添付画像を参照)。 MiddleViewには、Superview制約の先頭と末尾、topto topButton制約、bottom to bottomButton制約があります。そして最後に、bottomButtonには、Superview制約の先頭、末尾、末尾、およびtopからmiddleView制約があります。

制約が作成されて追加されたため、mySubviewがcontainerViewに合わせて拡大縮小するようにしたいのですが、代わりにmySubviewが非常に大きくなり、containerViewをクリップします。

以下にスクリーンショットを示します。

MyViewController.xib、タイトルの下の青い長方形は私のコンテナビューで、IBOutlet containerViewがあります。

http://i33.tinypic.com/14o3lmd.png

MySubview.xib

http://i37.tinypic.com/344ukk3.png

そして最後に、結果は間違っています。

http://i34.tinypic.com/nbyqua.png

代わりに、スクリーンショットを取得するためだけに偽造したこれが必要です。

IPhone 4では、

http://tinypic.com/r/w9fp5e/4

IPhone 5では、

http://tinypic.com/r/2z8nldv/4

偽のスクリーンショットでわかるように、containerViewがさまざまな電話画面サイズに合わせて少し拡大縮小している場合でも、mySubviewはcontainerViewに合わせて拡大縮小します。

私が情報で行き過ぎていないことを願っています。どんな助けも素晴らしいでしょう。私は近くにいるように感じますが、1つの重要なステップが欠落している必要があります。 Grrrrr。

30
Feta

いくつかの考え:

  1. これは基本的に、変数名の奇妙さ以外は問題ありません。ローカル変数containerViewself.subView、ただし他のすべての行は異なる変数、クラスプロパティ、self.containerViewcontainerViewクラスプロパティを設定した行を省略しましたか?しかし、私がそれを修正したとき、あなたのコードはうまく機能しました。

  2. 変更がframe設定にまだ反映されないため、制約を設定した直後にframeを見ようとしていないことを確認してください。 [containerView layoutIfNeeded];制約に基づいてすべてを強制的に再レイアウトする場合。また、frame設定を確認したい場合は、viewDidAppearの後までそれらの値を見ることを延期することをお勧めします(つまり、viewDidLoadがビュー構築プロセスの早すぎる)。

  3. コードの微調整(および問題とは無関係)ですが、コンテナビュー内で制約を設定する場合、NSLayoutAttributeTopNSLayoutAttributeLeadingだけでなく、多くの場合を設定します、しかしNSLayoutAttributeBottomNSLayoutAttributeTrailingNSLayoutAttributeWidthNSLayoutAttributeHeightではなく)。コードと同じことを実現しますが、ゼロ以外の値を使用する場合は、より直感的です。

    とにかく、私は次のコードを実行し、あなたのものを並べ替えただけで、うまく機能します:

    - (IBAction)didTouchUpInsideAddView:(id)sender
    {
        UIView *containerView = self.containerView;
        UIView *newSubview = [[UIView alloc] initWithFrame:CGRectZero]; // initializing with CGRectZero so we can see it change
        newSubview.translatesAutoresizingMaskIntoConstraints = NO;
        newSubview.backgroundColor = [UIColor lightGrayColor];
        [containerView addSubview:newSubview];
    
        [containerView addConstraint:[NSLayoutConstraint constraintWithItem:newSubview
                                                                  attribute:NSLayoutAttributeTop
                                                                  relatedBy:NSLayoutRelationEqual
                                                                     toItem:containerView
                                                                  attribute:NSLayoutAttributeTop
                                                                 multiplier:1.0
                                                                   constant:0.0]];
    
        [containerView addConstraint:[NSLayoutConstraint constraintWithItem:newSubview
                                                                  attribute:NSLayoutAttributeLeading
                                                                  relatedBy:NSLayoutRelationEqual
                                                                     toItem:containerView
                                                                  attribute:NSLayoutAttributeLeading
                                                                 multiplier:1.0
                                                                   constant:0.0]];
    
        [containerView addConstraint:[NSLayoutConstraint constraintWithItem:newSubview
                                                                  attribute:NSLayoutAttributeBottom
                                                                  relatedBy:NSLayoutRelationEqual
                                                                     toItem:containerView
                                                                  attribute:NSLayoutAttributeBottom
                                                                 multiplier:1.0
                                                                   constant:0.0]];
    
        [containerView addConstraint:[NSLayoutConstraint constraintWithItem:newSubview
                                                                  attribute:NSLayoutAttributeTrailing
                                                                  relatedBy:NSLayoutRelationEqual
                                                                     toItem:containerView
                                                                  attribute:NSLayoutAttributeTrailing
                                                                 multiplier:1.0
                                                                   constant:0.0]];
    
        // the frame is still `CGRectZero` at this point
    
        NSLog(@"newSubview.frame before = %@", NSStringFromCGRect(newSubview.frame));
    
        // if not doing this in `viewDidLoad` (e.g. you're doing this in
        // `viewDidAppear` or later), you can force `layoutIfNeeded` if you want
        // to look at `frame` values. Generally you don't need to do this unless
        // manually inspecting `frame` values or when changing constraints in a
        // `animations` block of `animateWithDuration`.
    
        [containerView layoutIfNeeded];
    
        // everything is ok here
    
        NSLog(@"containerView.bounds after = %@", NSStringFromCGRect(containerView.bounds));
        NSLog(@"newSubview.frame after = %@", NSStringFromCGRect(newSubview.frame));
    }
    
  4. visual format language を使用して、そのコードを少し簡素化できます。例:

    NSDictionary *views = NSDictionaryOfVariableBindings(newSubview);
    
    [containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[newSubview]|"
                                                                          options:0
                                                                          metrics:nil
                                                                            views:views]];
    [containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[newSubview]|"
                                                                          options:0
                                                                          metrics:nil
                                                                            views:views]];
    

    視覚的な形式の言語を使用すると、制約を簡単に正しく取得できます。エラーが発生しにくい(少なくとも私にとっては)。ただし、視覚形式言語では表現できない制約がいくつかあります。その場合は、説明した構文に戻ります。

  5. 修正した質問で、サブビュー用のinitメソッドを示します。これはanotheraddSubviewを実行します。そこにも制約を設定する必要があります。一番下の行では、addSubviewを実行するたびに、制約を設定する必要があります.

    - (id)init
    {
        if(self = [super init])
        {
            NSArray *nibArray = [[NSBundle mainBundle]loadNibNamed:@"MySubview" owner:self options:nil];
            UIView *subview = [nibArray objectAtIndex:0];
            subview.translatesAutoresizingMaskIntoConstraints = NO;
    
            [self addSubview:subview];
    
            NSDictionary *views = NSDictionaryOfVariableBindings(subview);
            [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[subview]|"
                                                                         options:0
                                                                         metrics:nil
                                                                           views:views]];
            [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[subview]|"
                                                                         options:0
                                                                         metrics:nil
                                                                           views:views]];
        }
        return self;
    }
    
58
Rob

問題では、「私の新しいサブビューはコンテナビューに一致するようにスケーリングされていません」と述べていますが、説明からはそうだと思います-問題は、コンテナビューに固定サイズがないことです。

コンテナービューの幅と高さを固定するようにコンテナービューを設定する場合、次の呼び出しも必要になると思います。

[self.containerView layoutSubviews]

制約を更新した後に強制的にサイズ変更します。

また、テキストベースのフォーマットを使用するように交換することをお勧めします。「H:| [newSubview] |」のような行を上の行と交換できますおよび「V:| [newSubview] |」

1
James