「frameとboundsの違いってなんやねん!」となったので調べました。
そもそもframeとboundsは
UIViewのサブクラスが持っているプロパティ。CGRectを返す。
英単語の意味的にはWeblio英和辞書によると
frame
a 窓枠.
b 額縁.
c 背景.
d (温床の)枠組み,フレーム,温床.
e (刺繍(ししゆう)などの)製作台,掛け枠.
f 複数形で(眼鏡の)枠,フレーム.
g (養蜂の取りはずし可能の)箱形のフレーム.
要するに"枠"という意味(?)
bounds
1境界,限界(内); 立ち入り許可区域.
2限度,範囲; 境界線,限界
という意味らしい
CGRectとは
公式ドキュメントによると
A structure that contains the location and dimensions of a rectangle.
と定義されており、
意訳すると
矩形の寸法を返す構造体となります。
frameとboundsの違いは
そもそもframeとboundsが何者かがわかったので、いよいよ本題です。
frame
要素自身を基準とした相対的な座標・大きさを返すプロパティ(superviewが基準)
bounds
要素の親を基準とした相対的な座標・大きさを返すプロパティ(UIView自身が基準)
という違いがあるみたいです。
つまりどこを基準とするかが変わってくるみたいです。
サンプルコード
実際にコードを書いて検証します。
x: 200, y: 200に正岡子規の画像を配置してframeとboundsの値の違いを見ます。
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let imageView = UIImageView(image: UIImage(named: "shiki"))
// 指定した座標・大きさを設定
imageView.frame = CGRect(x: 200, y: 200, width: 100, height: 100);
print(
"frameから見たX\(imageView.frame.minX)\n",
"frameから見たY\(imageView.frame.minY)\n",
"boundsから見たX\(imageView.bounds.minX)\n",
"boundsから見たY\(imageView.bounds.minY)\n"
)
// viewにUIImageViewを追加
self.view.addSubview(imageView)
}
}
こうなりました。
座標は親要素をframeから見ると(200, 200)の所に、要素自身を基準にboundsから見ると(0, 0)で基準によって違うに対して大きさは一緒なのが分かります。
活用例
親要素を基準に子要素の大きさを指定することが出来ます。
また、こういった場合はframeよりboundsを使うほうが良いです。boundsは要素自身を基準とした座標・大きさを持っているからです。
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let imageView = UIImageView(image: UIImage(named: "shiki"))
// 大きさ(親要素の半分の正方形)
imageView.frame.size = CGSize(width: view.bounds.width / 2, height: view.bounds.height / 2)
// 中心の座標(親要素の中心をframeから取る)
imageView.center = CGPoint(x: view.bounds.width / 2, y: view.bounds.height / 2)
// viewにUIImageViewを追加
self.view.addSubview(imageView)
}
}
注意点
また、UIViewを拡大・縮小したり、回転させるとframeの値は変わりますが、boundsの値は変わりません
override func viewDidLoad() {
super.viewDidLoad()
let rectangle = UIView(frame: .zero)
rectangle.backgroundColor = .blue
rectangle.frame.size = CGSize(width: 100, height: 200)
rectangle.center = CGPoint(x: view.bounds.width / 2, y: view.bounds.height / 2)
// 拡大前
print(rectangle.frame, rectangle.bounds) // (157.0, 348.0, 100.0, 200.0) (0.0, 0.0, 100.0, 200.0)
rectangle.transform = CGAffineTransform(scaleX: 2, y: 2)
// 拡大後
print(rectangle.frame, rectangle.bounds) // (107.0, 248.0, 200.0, 400.0) (0.0, 0.0, 100.0, 200.0)
view.addSubview(rectangle)
}
このようにスケールさせた後、frameの値は変化しているのに対して、boundsの値が変化していないことが分かります。