今回はViewの配置やサイズ指定で使うframe
とbounds
について違いを調べていこうと思います
違いを知らずに表示の不具合を起こす可能性があるので要注意です(まさに自分が体験しました...)
frameについて
公式ドキュメントにあるように親Viewから見た相対的な座標・大きさを返すプロパティです
つまり、親Viewの左上を原点とし、右へx,下へyへ移動した位置であるoriginと、width, heightからなるサイズであるsizeで構成される情報です
実際に見てみましょう。
まずは下記のようなimageViewを表示させる画面があります
そして次のように赤い背景色のViewを追加します。
@IBOutlet private weak var imageView: UIImageView! override func viewDidLoad() { super.viewDidLoad() let view = UIView() view.backgroundColor = .red view.frame = imageView.frame self.view.addSubview(view) }
追加するViewにimageViewのframeを指定して位置を決めています
このときのframeの情報をログで確認すると(0.0, 74.0, 414.0, 788.0)
となっています
右へ0,下へ74(safeArea + 30)へ移動した位置の幅414、高さ788のviewになります
右へ0,下へ74は親Viewの左上を原点としたもので、今回の場合にはViewControllerのViewになります
frameの値は回転すると変わってしまいます
デバイスを回転させる場合、ウィンドウは回転せず、ビュー コントローラーのビューが回転します
ウィンドウの視点からは、すべてが実質的にポートレートモードとなります
このため、subViewのframeの値が変わります
次のようにViewを回転させるとframeの値は変わります
@IBOutlet private weak var imageView: UIImageView! override func viewDidLoad() { super.viewDidLoad() let view = UIView() var transRotate = CGAffineTransform() let angle = 35 * CGFloat.pi / 180 transRotate = CGAffineTransform(rotationAngle: CGFloat(angle)); view.transform = transRotate view.backgroundColor = .red view.frame = imageView.frame self.view.addSubview(view) }
回転したときのframeの情報をログで確認すると(-188.55358909013347, 26.52377222547068, 791.1071781802668, 882.9524555490586)
となっています。
boundsについて
boundsは自身を左上を原点とし、右へx,下へyへ移動した位置であるoriginと、width, heightからなるサイズであるsizeで構成される情報です。
frameとの違いは、自身を起点としているので、回転してもboundsは変わりません。
次のように設定します
@IBOutlet private weak var imageView: UIImageView! override func viewDidLoad() { super.viewDidLoad() let view = UIView() view.backgroundColor = .red view.bounds = imageView.bounds self.view.addSubview(view) }
このときのboundsの情報をログで確認すると(0.0, 74.0, 414.0, 788.0)
となっています
ここまではframeと同じ結果です。
次に回転させたときを確認します。
@IBOutlet private weak var imageView: UIImageView! override func viewDidLoad() { super.viewDidLoad() let view = UIView() var transRotate = CGAffineTransform() let angle = 35 * CGFloat.pi / 180 transRotate = CGAffineTransform(rotationAngle: CGFloat(angle)); view.transform = transRotate view.backgroundColor = .red view.bounds = imageView.bounds self.view.addSubview(view) }
このときのboundsの情報をログで確認すると(0.0, 74.0, 414.0, 788.0)
となっていて、回転させても値は変わりません
結論
ここまでframeとboundsの違いを説明しましたが、結局どちらを使った方がいいのでしょうか?
結果的にorigin(左上の位置)やwidthやheightを使う場合には回転したり、拡大・縮小などで変わってしまう可能性があるので、boundsを使うことを優先的に考えるのがいいと思います
例えば、画像と画像を合成するときに2つの画像の起点を合わせないと変な画像になるなど、想定外のことが発生する可能性は多少なりともあるのでframeを使う場合には気をつけないといけないです