[iOS] frameとboundsの違いを理解する

「frameとboundsの違いってなんやねん！」となったので調べました。

# そもそもframeとboundsは
UIViewのサブクラスが持っているプロパティ。CGRectを返す。

英単語の意味的には[Weblio英和辞書によると](https://ejje.weblio.jp/)
### frame
>a 窓枠.
b 額縁.
c 背景.
d (温床の)枠組み，フレーム，温床.
e (刺繍(ししゆう)などの)製作台，掛け枠.
f 複数形で(眼鏡の)枠，フレーム.
g (養蜂の取りはずし可能の)箱形のフレーム.

要するに"枠"という意味(?)

### bounds
>1境界，限界(内); 立ち入り許可区域.
2限度，範囲; 境界線，限界

という意味らしい

## CGRectとは
[公式ドキュメント](https://developer.apple.com/documentation/coregraphics/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の値の違いを見ます。


```swift:ViewController.swift
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)
	}
		
}
```
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352602/733956bc-1dbc-abd6-83f7-4a47553556c5.png" width="50%">

この位置に正岡子規が居る時、結果は
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352602/fc715e4a-f6e3-ae2f-d082-c42781d9306d.png)



こうなりました。

座標は親要素をframeから見ると(200, 200)の所に、要素自身を基準にboundsから見ると(0, 0)で基準によって違うに対して大きさは一緒なのが分かります。

# 活用例

親要素を基準に子要素の大きさを指定することが出来ます。
また、こういった場合はframeよりboundsを使うほうが良いです。boundsは要素自身を基準とした座標・大きさを持っているからです。

```swift
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の値は変わりません

```swift

	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の値が変化していないことが分かります。



# 参考文献
- [What’s the difference between frame and bounds?](https://www.hackingwithswift.com/example-code/uikit/whats-the-difference-between-frame-and-bounds#:~:text=At%20its%20simplest%2C%20a%20view's,relative%20to%20its%20parent's%20space.&text=Remember%2C%20the%20bounds%20is%20relative,the%20view%20nothing%20has%20changed.)
- [UIViewのframeとboundsとcenter](https://qiita.com/mumei1/items/170dc761858f45ff232d)
- [Weblio英和辞書](https://ejje.weblio.jp/)