32

IB に UIView があり、その中に別の UIView があり、これをコンテナー ビューとして使用しています。コードでは、3 つの異なるビューを作成し、アプリの状態に応じて適切なビューをコンテナーのビューにアニメーション化します。3 つの異なるビューのうち、常に有効なのは 1 つだけです。問題は、シミュレーターで別の 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 の先頭と末尾の制約、および top から topButton への制約と、bottom から bottomButton への制約があります。そして最後に、bottomButton には、先頭、末尾、および下から Superview への制約と、上から 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

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

iPhone4では、

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

iPhone5では、

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

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

私が情報で船外に出なかったことを願っています。どんな助けでも素晴らしいでしょう。近づいたような気がしますが、重要なステップが 1 つ欠けているに違いありません。ぐらぐら。

4

2 に答える 2

59

いくつかの考え:

  1. これは、変数名の奇妙さを除けば、基本的には問題ないように見えます。ローカル変数containerViewは に等しいself.subViewですが、他のすべての行は別の変数、クラス プロパティを参照していますself.containerViewcontainerViewそのクラス プロパティを設定する行を省略しましたか? しかし、私がそれを修正したとき、あなたのコードはうまくいきました。

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

  3. コードの微調整 (および問題とは無関係) ですが、コンテナー ビュー内で制約を設定するときは、多くの場合、 and だけNSLayoutAttributeTopでなく ( andではなく)NSLayoutAttributeLeadingも設定します。コードと同じことを達成しますが、ゼロ以外の値を使用すると、より直感的になります。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. ビジュアル フォーマット 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、サブビューのメソッドを示しています。これは別の addSubview. そこにも制約を設定する必要があります。要するに、どこにいても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;
    }
    
于 2013-04-22T23:23:57.193 に答える
1

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

コンテナビューの幅と高さを固定するように設定した場合は、呼び出す必要があるかもしれません

[self.containerView layoutSubviews]

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

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

于 2013-04-22T23:16:35.120 に答える