Cocoa:フレームと境界の違いは何ですか?
-
06-07-2019 - |
質問
UIView
およびそのサブクラスにはすべて、プロパティ frame
および bounds
があります。違いは何ですか?
解決
境界 noreferrer "> UIView は、長方形。独自の座標系(0,0)に対する位置(x、y)およびサイズ(width、height)として表されます。
フレーム noreferrer "> UIView は、長方形、含まれるスーパービューに対する位置(x、y)およびサイズ(width、height)として表されます。
つまり、スーパービューの25,25(x、y)に位置するサイズが100x100(幅x高さ)のビューを想像してください。次のコードは、このビューの境界とフレームを出力します。
// This method is in the view controller of the superview
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"bounds.origin.x: %f", label.bounds.origin.x);
NSLog(@"bounds.origin.y: %f", label.bounds.origin.y);
NSLog(@"bounds.size.width: %f", label.bounds.size.width);
NSLog(@"bounds.size.height: %f", label.bounds.size.height);
NSLog(@"frame.origin.x: %f", label.frame.origin.x);
NSLog(@"frame.origin.y: %f", label.frame.origin.y);
NSLog(@"frame.size.width: %f", label.frame.size.width);
NSLog(@"frame.size.height: %f", label.frame.size.height);
}
このコードの出力は次のとおりです。
bounds.origin.x: 0
bounds.origin.y: 0
bounds.size.width: 100
bounds.size.height: 100
frame.origin.x: 25
frame.origin.y: 25
frame.size.width: 100
frame.size.height: 100
つまり、どちらの場合も、境界線とフレームのどちらを見るかに関係なく、ビューの幅と高さは同じであることがわかります。異なるのは、ビューのX、Y配置です。境界の場合、これらの座標はビュー自体に関連するため、x座標とy座標は0,0です。ただし、フレームのx座標とy座標は、親ビュー内のビューの位置に相対的です(以前に25,25にあると言いました)。
UIViewsをカバーする優れたプレゼンテーションもあります。スライド1〜20をご覧ください。フレームと境界の違いを説明するだけでなく、視覚的な例を示しています。
他のヒント
簡単な回答
frame = 親ビューの座標系
を使用したビューの位置とサイズ- 重要:ビューを親に配置する
境界 = 独自の座標系
を使用したビューの位置とサイズ- 重要:ビューのコンテンツまたはサブビューをその中に配置する
詳細な回答
フレームを思い出すために、壁の額縁を思い浮かべます。額縁は、ビューの境界のようなものです。私は壁のどこにでも写真を掛けることができます。同様に、親ビュー(スーパービューとも呼ばれます)内の任意の場所にビューを配置できます。親ビューは壁のようなものです。 iOSの座標系の原点は左上です。ビューフレームのx-y座標を(0、0)に設定することで、スーパービューの原点にビューを置くことができます。これは、壁の左上隅に写真を掛けるようなものです。右に移動するにはxを増やし、下に移動するにはyを増やします。
バウンドを覚えやすくするために、バスケットボールコートを思い浮かべます。時々バスケットボールがバウンドアウトされます。あなたはバスケットボールコート全体にボールをドリブルしていますが、コート自体がどこにあるかはあまり気にしません。ジム、屋外の高校、家の前などにあります。関係ありません。あなたはただバスケットボールをしたいだけです。同様に、ビューの境界の座標系は、ビュー自体のみを考慮します。ビューが親ビューのどこにあるかについては何も知りません。境界の原点(デフォルトではポイント(0、0))は、ビューの左上隅です。このビューに含まれるサブビューはすべて、この点に関連して配置されます。バスケットボールをコートの左前隅に持っていくようなものです。
フレームと境界を比較しようとすると、混乱が生じます。しかし、実際には最初に見えるほど悪くはありません。理解を助けるためにいくつかの写真を使用しましょう。
フレームと境界
左側の最初の図では、親ビューの左上にビューがあります。 黄色の長方形はビューのフレームを表します。右側にはビューが再び表示されますが、今回は親ビューは表示されません。これは、境界が親ビューについて知らないためです。 緑の長方形はビューの境界を表します。両方の画像の赤い点は、フレームまたは境界の原点を表します。
Frame
origin = (0, 0)
width = 80
height = 130
Bounds
origin = (0, 0)
width = 80
height = 130
そのため、フレームと境界はその写真ではまったく同じでした。それらが異なる例を見てみましょう。
Frame
origin = (40, 60) // That is, x=40 and y=60
width = 80
height = 130
Bounds
origin = (0, 0)
width = 80
height = 130
フレームのx-y座標を変更すると、親ビューでフレームが移動することがわかります。ただし、ビュー自体のコンテンツはまったく同じように見えます。境界には、何かが違うという考えがありません。
これまで、フレームと境界の両方の幅と高さはまったく同じでした。ただし、常にそうとは限りません。ビューを時計回りに20度回転するとどうなるか見てみましょう。 (回転は変換を使用して行われます。ドキュメントおよびこれらの表示およびレイヤーの例をご覧ください。)
Frame
origin = (20, 52) // These are just rough estimates.
width = 118
height = 187
Bounds
origin = (0, 0)
width = 80
height = 130
境界はまだ同じであることがわかります。彼らはスティルl何が起こったのかわからない!ただし、フレーム値はすべて変更されています。
フレームと境界の違いを見るのが少し簡単になりましたね。記事おそらくフレームと境界を理解していないビューフレームを
として定義します...そのビューの親に関するそのビューの最小の境界ボックス そのビューに適用される変換を含む座標系。
ビューを変換すると、フレームが未定義になることに注意することが重要です。したがって、実際には、上の画像の回転した緑の境界の周りに描いた黄色のフレームは実際には存在しません。つまり、回転、拡大縮小、またはその他の変換を行う場合、フレーム値を使用しないでください。ただし、境界値は引き続き使用できます。 Appleのドキュメントは警告しています:
重要:ビューの
transform
プロパティに恒等変換が含まれていない場合、そのビューのフレームは定義されていないため、 自動サイズ変更動作の結果。
自動サイズ変更についてはやや残念です。しかし、できることはあります。
ビューの
transform
プロパティを変更する場合、すべて 変換は、中心点を基準にして実行されます 表示。
したがって、変換が完了した後に親内でビューを移動する必要がある場合は、 view.center
座標を変更することで実行できます。 frame
と同様に、 center
は親ビューの座標系を使用します。
さて、回転を取り除き、境界に注目しましょう。これまで、境界の原点は常に(0、0)のままでした。ただし、その必要はありません。ビューに、一度に表示するには大きすぎる大きなサブビューがある場合はどうなりますか?大きな画像を含む UIImageView
にします。再び上から2番目の画像を示しますが、今回はビューのサブビューのコンテンツ全体がどのようになるかを確認できます。
Frame
origin = (40, 60)
width = 80
height = 130
Bounds
origin = (0, 0)
width = 80
height = 130
画像の左上隅のみがビューの境界内に収まります。境界の原点座標を変更するとどうなるか見てみましょう。
Frame
origin = (40, 60)
width = 80
height = 130
Bounds
origin = (280, 70)
width = 80
height = 130
フレームはスーパービュー内で移動していませんが、境界矩形の原点はビューの別の部分から始まるため、フレーム内のコンテンツは変更されています。これは、 UIScrollView
とそのサブクラス(たとえば、 UITableView
)の背後にある全体的な考え方です。詳細については、 UIScrollViewについてをご覧ください。
フレームを使用する場合と境界を使用する場合
frame
は親ビューのビューの位置に関連するため、幅の変更やビュー間の距離の検索など、外側の変更を行うときに使用します親ビューの上部。
ビュー内での描画やサブビューの配置など、内向きの変更を行う場合は、境界
を使用します。また、変換を行った場合は、境界を使用してビューのサイズを取得します。
さらなる研究のための記事:
Appleドキュメント
以下のコードを実行してみてください
- (void)viewDidLoad {
[super viewDidLoad];
UIWindow *w = [[UIApplication sharedApplication] keyWindow];
UIView *v = [w.subviews objectAtIndex:0];
NSLog(@"%@", NSStringFromCGRect(v.frame));
NSLog(@"%@", NSStringFromCGRect(v.bounds));
}
このコードの出力は次のとおりです。
デバイスの向きが縦向きの場合
{{0, 0}, {768, 1024}}
{{0, 0}, {768, 1024}}
デバイスの向きが横向きの場合
{{0, 0}, {768, 1024}}
{{0, 0}, {1024, 768}}
明らかに、フレームと境界の違いを見ることができます
フレームは、そのスーパービューに関してUIViewを定義する長方形です。
bounds rect は、 NSViewの座標系を定義する値の範囲です。
i.e。この長方形内のすべてのものは、実際にはUIViewに表示されます。
frame は、スーパービューの座標系におけるビューの原点(左上隅)とサイズです。つまり、フレームの原点を変更することにより、スーパービューのビューを変換しますは独自の座標系のサイズと原点であるため、デフォルトでは境界の原点は(0,0)です。
ほとんどの場合、フレームと境界は合同ですが、フレーム((140,65)、(200,250))と境界((0,0)、(200,250))のビューがある場合、たとえばビューが右下に立つように傾けられた場合、境界は((0,0)、(200,250))のままになりますが、フレームはそうではありません。
フレームは、ビューをカプセル化/囲む最小の長方形になるため、フレームは(写真のように)((140,65)、(320,320))になります。
別の違いは、たとえば、境界が((0,0)、(200,200))のsuperViewがあり、このsuperViewに((20,20)、(100,100))のsubViewがあり、変更した場合です。 superViewが((20,20)、(200,200))にバインドされている場合、subViewフレームは((20,20)、(100,100))のままですが、スーパービュー座標系がオフセットされているため、(20,20)オフセットされます(20,20)。
これが誰かの助けになることを願っています。
スーパービューを基準にフレームを作成し、NSViewを基準に境界を設定します。
例:X = 40、Y =60。3つのビューも含まれています。この図は明確なアイデアを示しています。
上記の回答は、境界とフレームの違いを非常によく説明しています。
境界:独自の座標系によるビューのサイズと位置。
フレーム:ビューのサイズとそのSuperViewに対する相対的な位置。
その後、境界の場合、X、Yは常に「0」になるという混乱があります。 これは事実ではありません。これは、UIScrollViewとUICollectionViewでも理解できます。
境界のx、yが0でない場合。
UIScrollViewがあるとします。ページネーションを実装しました。 UIScrollViewには3つのページがあり、そのContentSizeの幅は画面幅の3倍です(ScreenWidthが320であると想定)。高さは一定です(200を想定)。
scrollView.contentSize = CGSize(x:320*3, y : 200)
3つのUIImageViewをサブビューとして追加し、フレームの x 値をよく見てください
let imageView0 = UIImageView.init(frame: CGRect(x:0, y: 0 , width : scrollView.frame.size.width, height : scrollView.frame.size.height))
let imageView1 : UIImageView.init( frame: CGRect(x:320, y: 0 , width : scrollView.frame.size.width, height : scrollView.frame.size.height))
let imageView2 : UIImageView.init(frame: CGRect(x:640, y: 0 , width : scrollView.frame.size.width, height : scrollView.frame.size.height))
scrollView.addSubview(imageView0)
scrollView.addSubview(imageView0)
scrollView.addSubview(imageView0)
-
ページ0: ScrollViewが0ページの場合、境界は (x:0、y:0、幅:320、高さ:200)
-
ページ1: スクロールしてページ1に移動します。
これで、境界は(x:320、y:0、幅:320、高さ:200)になります 独自の座標系に関して言ったことを思い出してください。そのため、「可視部」 ScrollViewの" x"には320で。imageView1のフレームを見てください。 - ページ2: スクロールしてページ2に移動します 境界:(x:640、y:0、幅:320、高さ:200) 再度、imageView2のフレームを見てください
UICollectionViewの場合も同じです。 collectionViewを見る最も簡単な方法は、それをスクロールして、その境界を印刷/記録することです。そうすれば、アイデアが得られます。
frame =親ビューの座標系を使用したビューの位置とサイズ
bounds =独自の座標系を使用したビューの位置とサイズ
ビューは、フレーム長方形と境界長方形の2つの長方形を使用して、サイズと位置を追跡します。フレーム長方形は、スーパービューの座標系を使用して、スーパービュー内のビューの位置とサイズを定義します。境界の四角形は、原点やスケーリングなど、ビューのコンテンツを描画するときに使用される内部座標系を定義します。図2-1は、左側のフレーム長方形と右側の境界長方形の関係を示しています。”
要するに、フレームはビューのスーパービューのアイディアであり、境界はビューのアイディアです。ビューごとに1つずつ、複数の座標系を持つことは、ビュー階層の一部です。