web-dev-qa-db-ja.com

UIViewフレーム、境界、および中央

これらのプロパティを正しい方法で使用する方法を知りたいです。

私が理解しているように、frameは私が作成しているビューのコンテナから使用できます。コンテナービューに対するビュー位置を設定します。そのビューのサイズも設定されます。

私が作成しているビューのコンテナからもcenterを使用できます。このプロパティは、コンテナに対するビューの位置を変更します。

最後に、boundsはビュー自身からの相対パスです。ビューの描画可能領域を変更します。

frameboundsの関係についてもっと詳しく教えてください。 clipsToBoundsおよびmasksToBoundsプロパティはどうですか?

314
Lorenzo B

私が尋ねた質問は何度も見られたので、私はそれについて詳細な答えを提供します。もっと正しい内容を追加したい場合は、気軽に修正してください。

まず、この問題について要約します。フレーム、境界、中心、およびそれらの関係。

フレームビューのframename__(CGRectname__)は、superviewname__の座標系におけるその矩形の位置です。デフォルトでは左上から始まります。

境界ビューのboundsname__(CGRectname__)は、ビューの四角形を独自の座標系で表します。

中心centername__は、CGPointnameの座標系で表されるsuperviewname__であり、ビューの正確な中心点の位置を決定します。

から引用UIView + positionこれらはリレーションシップです。前式のうち非公式方程式)

  • frame.Origin = center - (bounds.size / 2.0)

  • center = frame.Origin + (bounds.size / 2.0)

  • frame.size = bounds.size

注:ビューが回転している場合、これらの関係は適用されません。より詳しい情報は、The Kitchen Drawerから撮った以下の画像をご覧になることをお勧めします。 スタンフォードCS193pコースに基づく。クレジットは@ Rhubarbに行きます。

Frame, bounds and center

framename__を使用すると、そのsuperviewname__内でビューの位置やサイズを変更できます。たとえば、特定のサブビューを作成するときなどに、通常はsuperviewname__から使用できます。例えば:

// view1 will be positioned at x = 30, y = 20 starting the top left corner of [self view]
// [self view] could be the view managed by a UIViewController
UIView* view1 = [[UIView alloc] initWithFrame:CGRectMake(30.0f, 20.0f, 400.0f, 400.0f)];    
view1.backgroundColor = [UIColor redColor];

[[self view] addSubview:view1];

viewname__内に描画するための座標が必要な場合は、通常boundsname__を参照します。典型的な例は、最初のインセットとしてviewname__サブビュー内に描画することです。サブビューを描画するには、スーパービューのboundsname__を知る必要があります。例えば:

UIView* view1 = [[UIView alloc] initWithFrame:CGRectMake(50.0f, 50.0f, 400.0f, 400.0f)];    
view1.backgroundColor = [UIColor redColor];

UIView* view2 = [[UIView alloc] initWithFrame:CGRectInset(view1.bounds, 20.0f, 20.0f)];    
view2.backgroundColor = [UIColor yellowColor];

[view1 addSubview:view2];

ビューのboundsname__を変更すると、さまざまな動作が発生します。たとえば、boundssizename__を変更すると、framename__も変更されます(その逆も同様)。変更はビューのcentername__を中心に行われます。以下のコードを使用して、何が起こるのか見てください。

NSLog(@"Old Frame %@", NSStringFromCGRect(view2.frame));
NSLog(@"Old Center %@", NSStringFromCGPoint(view2.center));    

CGRect frame = view2.bounds;
frame.size.height += 20.0f;
frame.size.width += 20.0f;
view2.bounds = frame;

NSLog(@"New Frame %@", NSStringFromCGRect(view2.frame));
NSLog(@"New Center %@", NSStringFromCGPoint(view2.center));

さらに、boundsOriginname__を変更すると、その内部座標系のOriginname__も変更されます。デフォルトでは、Originname__は(0.0, 0.0)(左上隅)にあります。たとえば、view1Originname__を変更すると、view2の左上隅がview1の隅に接触していることがわかります(必要に応じて前のコードをコメントにします)。動機は非常に簡単です。 view1にその左上隅が(20.0, 20.0)の位置にあると言いますが、view2frameOriginname__は(20.0, 20.0)から始まるので、それらは一致します。

CGRect frame = view1.bounds;
frame.Origin.x += 20.0f;
frame.Origin.y += 20.0f;
view1.bounds = frame; 

Originname__は、そのviewname__内のsuperviewname__の位置を表しますが、boundsname__センターの位置を表します。

最後に、boundsname__とOriginname__は関連概念ではありません。どちらもビューのframename__を派生させることができます(前の式を参照)。

View1のケーススタディ

これは、次のスニペットを使用したときに起こることです。

UIView* view1 = [[UIView alloc] initWithFrame:CGRectMake(30.0f, 20.0f, 400.0f, 400.0f)];
view1.backgroundColor = [UIColor redColor];

[[self view] addSubview:view1];

NSLog(@"view1's frame is: %@", NSStringFromCGRect([view1 frame]));
NSLog(@"view1's bounds is: %@", NSStringFromCGRect([view1 bounds]));
NSLog(@"view1's center is: %@", NSStringFromCGPoint([view1 center]));

相対画像です。

enter image description here

[self view]の範囲を以下のように変更した場合、代わりにこれが起こります。

// previous code here...
CGRect rect = [[self view] bounds];
rect.Origin.x += 30.0f;
rect.Origin.y += 20.0f;
[[self view] setBounds:rect];

相対画像です。

enter image description here

ここでは[self view]にその左上隅が(30.0、20.0)の位置にあると言っていますが、view1のフレームOriginは(30.0、20.0)から始まるので、それらは一致します。

追加の参照(必要に応じて他の参照で更新するため)

clipsToBoundsname__について(source Apple doc)

この値をYESに設定すると、サブビューはレシーバーの境界にクリップされます。 NOに設定すると、フレームがレシーバの表示範囲を超えて伸びるサブビューは切り取られません。デフォルト値はNOです。

つまり、ビューのframename__が(0, 0, 100, 100)でそのサブビューが(90, 90, 30, 30)の場合、そのサブビューの一部しか表示されません。後者は、親ビューの範囲を超えません。

masksToBoundsname__はclipsToBoundsname__と同等です。 UIViewname__ではなく、このプロパティはCALayername__に適用されます。内部では、clipsToBoundsname__はmasksToBoundsname__を呼び出します。詳細については、 を参照してください。UIViewのclipsToBoundsとCALayerのmasksToBoundsの関係はどうですか?

568
Lorenzo B

この質問にはすでに良い答えがありますが、もう少し詳しく説明します。 私の完全な答えはここにあります。

フレームを思い出すのを助けるために、私は壁の上の額縁を考えます。絵が壁のどこにでも動くことができるように、ビューのフレームの座標系はスーパービューです。 (壁=スーパービュー、フレーム=ビュー)

範囲を覚えやすくするために、私はバスケットボールコートの範囲を考えます。バスケットボールは、ビューの境界の座標系がビュー自体の中にあるように、コート内のどこかにあります。 (コート=ビュー、バスケットボール/選手=ビュー内のコンテンツ)

フレームのように、view.centerもスーパービューの座標にあります。

枠と境界 - 例1

黄色い長方形はビューのフレームを表します。緑色の長方形はビューの境界を表します。両方の画像の赤い点は、フレームの原点またはそれらの座標系内の境界を表します。

Frame
    Origin = (0, 0)
    width = 80
    height = 130

Bounds 
    Origin = (0, 0)
    width = 80
    height = 130

enter image description here


例2

Frame
    Origin = (40, 60)  // That is, x=40 and y=60
    width = 80
    height = 130

Bounds 
    Origin = (0, 0)
    width = 80
    height = 130

enter image description here


実施例3

Frame
    Origin = (20, 52)  // These are just rough estimates.
    width = 118
    height = 187

Bounds 
    Origin = (0, 0)
    width = 80
    height = 130

enter image description here


実施例4

これは例2と同じですが、今回はビューの境界全体にクリップされていない場合のようにビューの内容全体が表示される点が異なります。

Frame
    Origin = (40, 60)
    width = 80
    height = 130

Bounds 
    Origin = (0, 0)
    width = 80
    height = 130

enter image description here


実施例5

Frame
    Origin = (40, 60)
    width = 80
    height = 130

Bounds 
    Origin = (280, 70)
    width = 80
    height = 130

enter image description here

繰り返しになりますが、私の答えについては こちら をご覧ください。

131
Suragch

この画像は、枠、境界線などを理解するのに最も役立ちます。

enter image description here

また、画像が回転したときのframe.size != bounds.sizeにも注意してください。

88
Erben Mo

CALayerの観点から考えれば、すべてがより明確になります。

Frameは、実際にはビューやレイヤのまったく異なるプロパティではありません。境界、位置(UIViewの中心)、およびトランスフォームから計算された仮想プロパティです。

そのため、基本的にレイヤ/ビューのレイアウトはこれら3つのプロパティ(およびanchorPoint)によって実際にどのように決定されますか。また、変換を変更しても境界は変更されません。

3
coolbeet

この記事への詳しい説明と非常によい答えがあります。 WWDC 2011ビデオのFrame、Bounds、Center、Transform、Bounds Originの意味についてのビジュアル表現による別の説明があることを言及したいだけですUIKitについて理解する@ 4:22から20:10までのレンダリング

1
Wael Showair

上記の答えを読んだ後、ここに私の解釈を加えます。

オンラインブラウジング、WebブラウザがWebページを表示する場所と大きさを決定するframeであるとします。 ブラウザのスクローラは、Webページのどの部分を表示するかを決めるbounds.Originです。 bounds.Originは理解するのが難しいです。学習するための最良の方法は、シングルビューアプリケーションを作成し、これらのパラメータを変更してサブビューがどのように変化するかを確認することです。

- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.

UIView *view1 = [[UIView alloc] initWithFrame:CGRectMake(100.0f, 200.0f, 200.0f, 400.0f)];
[view1 setBackgroundColor:[UIColor redColor]];

UIView *view2 = [[UIView alloc] initWithFrame:CGRectInset(view1.bounds, 20.0f, 20.0f)];
[view2 setBackgroundColor:[UIColor yellowColor]];
[view1 addSubview:view2];

[[self view] addSubview:view1];

NSLog(@"Old view1 frame %@, bounds %@, center %@", NSStringFromCGRect(view1.frame), NSStringFromCGRect(view1.bounds), NSStringFromCGPoint(view1.center));
NSLog(@"Old view2 frame %@, bounds %@, center %@", NSStringFromCGRect(view2.frame), NSStringFromCGRect(view2.bounds), NSStringFromCGPoint(view2.center));

// Modify this part.
CGRect bounds = view1.bounds;
bounds.Origin.x += 10.0f;
bounds.Origin.y += 10.0f;

// incase you need width, height
//bounds.size.height += 20.0f;
//bounds.size.width += 20.0f;

view1.bounds = bounds;

NSLog(@"New view1 frame %@, bounds %@, center %@", NSStringFromCGRect(view1.frame), NSStringFromCGRect(view1.bounds), NSStringFromCGPoint(view1.center));
NSLog(@"New view2 frame %@, bounds %@, center %@", NSStringFromCGRect(view2.frame), NSStringFromCGRect(view2.bounds), NSStringFromCGPoint(view2.center));
0
NSTNF