152
118

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

frameとboundsの理解をちょっとだけ深める

Posted at

UIViewのframeとbounds、どちらもViewのサイズや位置を決めるものですが、結構適当にframeを使っている方が多いのではないでしょうか?
いろんなサイトで解説されていますが、frameは親からの座標 / boundsは自分の座標といわれても???な感じでした。
差がよくわからない、そもそもなぜ2個あるんだと。

自分もまだ完全ではないですが、コードを書いて動かして理解した範囲でまとめてみます。

とはいうものの、frameとboundsだけでは理解しづらいです。
ここに center、transform を加えるとぐっと理解しやすくなります。


それぞれの関係を図にまとめるとこんな感じです(数値は座標のイメージで正確じゃないです)

ios_view_position.png

親Viewにグレーの子Viewを配置して、適当にtransformで位置・スケール・回転をずらしたイメージです。
左上のグレー枠が描画抜きで親からみた子Viewの場所、右下のななめになっているグレー枠がtransformの結果、実際に描画された子Viewです。

center/boundsはtransform前の配置座標、frameはtransform後の描画座標  というイメージです。
(※孫Viewまで考えると実描画位置という言い方はちょっとまずいのですが...)

Android的にいうと、 center/boundsがlayout座標、transformがAnimationでの移動、frameがAnimationで移動した結果描画される座標 というところでしょうか。


よって、自分の半分のサイズの子Viewを追加したい というときにframeを使うとまずいです。
もしtransformが変更されていて大きさが変わっていた場合意図した動作になりません。

仮に(100,60)のViewがあり、大きさ半分(50,30)の子Viewを追加したいとします。
このとき、transformで描画サイズが倍になっていたとすると...?

UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 60)];
view.transform = CGAffineTransformMakeScale(2, 2);   //2倍に

//さぁこのviewに大きさ半分のView(幅50, 高さ30)を追加するぞ

//だめな例。frameを使う
CGFloat childW = CGRectGetWidth(view.frame) / 2;
CGFloat childH = CGRectGetHeight(view.frame) / 2;
childView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, childW, childH)];
[view addSubview:childView];
//transformでviewの描画サイズが倍なので、childW=100,childH=60となり意図しない結果になる

//正しい例。boundsを使う
CGFloat childW = CGRectGetWidth(view.bounds) / 2;
CGFloat childH = CGRectGetHeight(view.bounds) / 2;
//この方法ならtransformに関わらずchildW=50, childH=30で意図通り

これは極端な例ではありますが、frameとboundsで明確に結果に差が出ます。
transform前のサイズがほしいのか、後のサイズがほしいのか を明確に意識して使い分けましょう。

centerも同様です。
transformで位置を動かす前の場所がほしいときはcenter、
実際の描画位置を見たいときは frame をもちいましょう。


また、適当にframeを設定するのも注意です。
特に回転がかかっている場合、viewのboundsがどう変わるのか予測が難しいです
試しに45度回転がかかった状態で適当にframeを設定したとしましょう。
frameが変わる、ということはそれに関連するcenter/boundsが変わることを意味します。

このとき、次のような問題が発生します

qiita_image.png

赤線が新しいframeです。ではそのときboundsはどういう値になればいいのか。
青い3つの線がboundsのイメージです。

でも3つの青線の四角形、すべてが設定したframeを満たしてますよね?
条件を満たす値が複数存在するということは、 どうなるかよくわかりません

自分がこういうコードを書いて実験したときは、frame操作のたびにboundsがゆがみ、最後にはboundsの高さが0になり見えなくなりました。
内部的にはちゃんと逆行列のような計算が走ってるとは思いますが、結果が予測困難です。

よって、frameで大きさを変えるときは要注意です。
もちろん、transformが変わっていないことが分かっている状態ならOKです。


まだよくわかっていないのがboundsのoriginを(0, 0)以外にしたときです。
左上の座標というより、centerからのオフセットという印象を受けます。
ただ子Viewは一切オフセットされなかったので、ややトリッキーな印象です。
(使うシーンはあるのだろうか...詳しい人教えてください...)

152
118
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
152
118

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?