web-dev-qa-db-ja.com

自動レイアウト制約を使用しているときに、ビューの現在の幅と高さを取得するにはどうすればよいですか?

ビューのサイズはxibでしか取得できないため、フレームプロパティについては説明していません。制約のためにビューのサイズが変更されるとき(回転後、またはイベントへの応答時)について話しています。現在の幅と高さを取得する方法はありますか?

幅と高さの制約を探して制約を反復処理してみましたが、それはあまりきれいではなく、固有の制約がある場合は失敗します(2つを区別できないため)。また、実際に幅と高さの制約がある場合にのみ機能しますが、他の制約に依存してサイズを変更する場合は機能しません。

なぜこれが私にとってそんなに難しいのですか。 ARG!

100
yuf

答えは[view layoutIfNeeded]です。

その理由は次のとおりです。

ビューの現在の幅と高さを取得するには、view.bounds.size.widthview.bounds.size.height(または、view.transformで遊んでいない限り同等のフレーム)を調べます。

既存の制約で示される幅と高さが必要な場合、自動レイアウトシステムの制約解決ロジック全体を再実装する必要があるため、答えは制約を手動で検査することではありません。代わりに、自動レイアウトにそのレイアウトを更新するように要求するだけです、制約を解決し、view.boundsの値を更新します解決策を修正してから、view.boundsを調べます。

自動レイアウトにレイアウトの更新を依頼するにはどうすればよいですか?実行ループの次のターンで自動レイアウトでレイアウトを更新する場合は、[view setNeedsLayout]を呼び出します。

ただし、レイアウトをすぐに更新して、新しい境界値にすぐにアクセスできるようにする場合後で現在の関数内で、または実行ループのターンの前の別のポイントで、 [view setNeedsLayout]および[view layoutIfNeeded]を呼び出します。

あなたは2番目の質問をしました:「高さ/幅の制約を直接参照していない場合、どのように変更できますか?」.

IBで制約を作成する場合、最適な解決策は、View ControllerまたはビューでIBOutletを作成して、直接参照できるようにすることです。コードで制約を作成した場合は、作成時に内部の弱いプロパティの参照を保持する必要があります。他の誰かが制約を作成した場合、ビューのview.constraintsプロパティ、および場合によってはビュー階層全体を調べ、重要なNSLayoutConstraintを見つけるロジックを実装することで、制約を見つける必要があります。これはおそらく間違った方法です。なぜなら、その質問に対する簡単な答えが保証されていない場合、どの特定の制約が境界サイズを決定したかを効果的に決定する必要があるからです。最終的な境界値は、複数の優先順位などを含む複数の制約の非常に複雑なシステムの解決策になる可能性があるため、単一の制約が最終値の「原因」になることはありません。

235
algal

UITableViewで設定された制約に基づいてサイズを変更するUIStoryboardに上下の境界線を追加する必要があるという同様の問題がありました。 - (void)viewDidLayoutSubviewsで更新された制約にアクセスできました。これは、ビューをサブクラス化してそのレイアウトメソッドをオーバーライドする必要がないように便利です。

/*** SET TOP AND BOTTOM BORDERS ON TABLE VIEW ***/
- (void)addBorders
{
    CALayer *topBorder           = [CALayer layer];
    topBorder.frame              = CGRectMake(0.0f, self.tableView.frame.Origin.y, 320.0f, 0.5f);
    topBorder.backgroundColor    = [UIColor redColor].CGColor;

    CALayer *bottomBorder        = [CALayer layer];
    bottomBorder.frame           = CGRectMake(0.0f, (self.tableView.frame.Origin.y + self.tableView.frame.size.height), 320.0f, 0.5f);
    bottomBorder.backgroundColor = [UIColor redColor].CGColor;

    [self.view.layer addSublayer:topBorder];
    [self.view.layer addSublayer:bottomBorder];
}

/*** GET AUTORESIZED FRAME DIMENSIONS ***/
- (void)viewDidLayoutSubviews{
    [self addBorders];
}

viewDidLayoutSubviewメソッドからメソッドを呼び出さないと、下の境界は画面外のどこかにあるため、上の境界のみが正しく描画されます。

8
Brandon Read

まだそのような問題に直面している可能性のある人、特にTableviewCellで。

メソッドをオーバーライドするだけです:

-(void)layoutSubviews
{
//your code here like drawing a shadow
}

UITableViewCellまたはUICollectionViewCellの場合、セルのサブクラスを作成し、同じメソッドをオーバーライドします。

-(void)layoutSubviews
{
//your code here like drawing a shadow
}
4
Mayank Pahuja

-(void)viewWillAppear:(BOOL)animatedを使用して[self.view layoutIfNeeded];を呼び出します-試した通りに動作します。

-(void)viewDidLayoutSubviewsを使用すれば確実に機能しますが、UIが更新/変更を要求するたびにこのメソッドが呼び出されるためです。これは管理が難しくなります。ソフトキーは、bool変数を使用して、このような呼び出しのループを回避することです。 viewWillAppearを使用してください。 viewWillAppearは、ビューが再度ロードされた場合(再割り当てなし)に呼び出されることも忘れないでください。

3
user3693546

フレームはまだ有効です。最終的に、ビューは自身のレイアウトにframeプロパティを使用します。すべての制約に基づいてそのフレームを計算します。制約は初期レイアウトにのみ使用されます(また、回転後などのビューでlayoutSubviewsが呼び出される場合)。その後、位置情報はframeプロパティにあります。それとも別の方法で見ていますか?

2
borrrden