くま's Tech系Blog

基本的には技術で学んだことを書き留めようと思います。雑談もやるかもね!

frameとboundsの違いについて

今回はViewの配置やサイズ指定で使うframeboundsについて違いを調べていこうと思います

違いを知らずに表示の不具合を起こす可能性があるので要注意です(まさに自分が体験しました...)

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を使う場合には気をつけないといけないです

参照

developer.apple.com

developer.apple.com