【Swift】boundsとframeの違いと使い分け!Viewの座標と領域を取得
この記事からわかること
- SwiftのUIViewのboundsとframeの違いとは?
- 座標や領域を取得する方法
index
[open]
\ アプリをリリースしました /
友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-
posted withアプリーチ
環境
- Xcode:15.0.1
- iOS:17.1
- Swift:5.9
- macOS:Sonoma 14.1
UIViewのboundsとframeについて
SwiftでViewの座標や領域(横幅や縦幅)を取得できるプロパティがbounds
とframe
の2つ用意されています。両者ともUIViewクラスのプロパティとして定義されており、CGRect
型で値を取得することが可能です。
var frame: CGRect { get set }
var bounds: CGRect { get set }
CGRect
型は長方形(Rectangle)のサイズや座標を定義するための構造体です。CGRect
型のプロパティからViewのX座標やY座標、横幅(width)、縦幅(height)などそれぞれの取得することができます。
CGRect(x: 100, y: 100, width: 200, height: 150)
iOSデバイスは以下画像のように左上を(x:0,y:0)
としたX軸/Y軸として管理されています。
frameプロパティ
var frame: CGRect { get set }
frame
は親ビュー(superview)の座標系における対象ビュー(subview)の位置とサイズを表すプロパティです。基準となるのは親ビューなのでX/Y座標に格納される値は対象のViewの左隅上が親ビューのX/Y座標のどこにあるかを示します。self.view
を親Viewとする場合、以下のように指定すると親View(self.view)は画面いっぱいに広がっているので(x:100,y:100)
の位置に対象View(area)の左隅上が来るように配置されます。
let area = UIView()
area.frame = CGRect(x: 100, y: 100, width: 200, height: 150)
area.backgroundColor = .gray
self.view.addSubview(area)
さらにsubviewを追加した場合
親Viewの座標なので親Viewをareaとしてさらにsubviewを追加する場合は親View(area)の左隅上を(x:0,y:0)として対象ビュー(label)が配置されます。
let label = UILabel()
label.frame = CGRect(x: 10, y: 10, width: 180, height: 130)
label.text = "HELLO"
label.backgroundColor = .orange
area.addSubview(label)
値を取得する
そのため取得できる値も親Viewを起点とした時の座標になります。
print("area.frame:\(area.frame)")
print("label.frame:\(label.frame)")
// area.frame:(100.0, 100.0, 200.0, 150.0)
// label.frame:(10.0, 10.0, 180.0, 130.0)
変更時にdraw(_:)は呼ばれない
frame
に変更を加えた際はdraw(_:)
メソッド(描画処理)は呼ばれずに自動更新されるようです。変更時にdraw(_:)
メソッドを呼ばれるようにしたい場合はcontentMode
プロパティにredraw
を指定します。
area.contentMode = .redraw
アニメーション対応
frame
はアニメーション対応しているプロパティなので値が変更された時に変化を滑らかに実行することが可能です。
UIView.animate(withDuration: 1.0) {
// 1秒後に値を変更する
area.frame = CGRect(x: 50, y: 50, width: 200, height: 150)
}
frameプロパティ〜まとめ〜
- CGRect型で値を取得/設定
- 指定するX/Y座標は自身の左隅上の位置
- 座標は親View(superview)を基準とした値
- 変更時にdraw(_:)は呼ばれない
- アニメーション対応
boundsプロパティ
bounds
は自身の座標系における対象ビュー(subview)の位置とサイズを表すプロパティです。基準となるのは自分自身なのでX/Y座標に格納される値は(x:0,y:0)になりますが、サイズはframe
プロパティで指定されている値と同じになります。
そのためbounds
プロパティにCGRect
型で値を指定しても変更されるのはサイズのみになります。
let area = UIView()
area.frame = CGRect(x: 100, y: 100, width: 200, height: 150)
area.bounds = CGRect(x: 0, y: 0, width: 300, height: 150)
area.backgroundColor = .gray
self.view.addSubview(area)
値を取得する
またbounds
プロパティの値を更新してもframe
プロパティの値も更新されます。
print("area.frame:\(area.frame)")
print("area.bounds:\(area.bounds)")
// area.frame:(50.0, 100.0, 300.0, 150.0)
// area.bounds:(0.0, 0.0, 300.0, 150.0)
変更時にdraw(_:)は呼ばれない
bounds
もframe
同様に変更を加えた際はdraw(_:)
メソッド(描画処理)は呼ばれずに自動更新されるようです。変更時にdraw(_:)
メソッドを呼ばれるようにしたい場合はcontentMode
プロパティにredraw
を指定します。
area.contentMode = .redraw
アニメーション対応
bounds
もアニメーション対応しているプロパティなので値が変更された時に変化を滑らかに実行することが可能です。
UIView.animate(withDuration: 1.0) {
// 1秒後に値を変更する
area.bounds = CGRect(x: 0, y: 0, width: 200, height: 200)
}
boundsプロパティ〜まとめ〜
- CGRect型で値を取得/設定
- X/Y座標を指定してもViewの位置変更されない
- 座標は自分自身基準なので(x:0,y:0)になる
- 変更時にdraw(_:)は呼ばれない
- アニメーション対応
frameとboundsの違い
frame
- 親ビューの座標系におけるビューの位置とサイズを表す
- 親ビューに対する相対的な位置やサイズを指定
- ビューの描画位置や表示位置を制御するのに用いる
bounds
- ビューのローカル座標系におけるサイズと位置を示す
- ビュー自体の描画や配置に関する操作を行うために使用
- 通常、原点は(0, 0)であり、ビューの幅と高さを指定する
Viewを変更(拡大/縮小)してもサイズは取得できる値は変わらない
Viewをスケーリング(拡大/縮小)した場合にframe
とbounds
プロパティに違いが現れます。frame
プロパティの値は2倍されたViewの座標とサイズになりますが、bounds
プロパティは元のサイズのままです。
let area = UIView()
area.frame = CGRect(x: 100, y: 100, width: 100, height: 100)
area.backgroundColor = .gray
self.view.addSubview(area)
// 2倍にスケーリング
area.transform = CGAffineTransform(scaleX: 2, y: 2)
print("area.frame:\(area.frame)")
print("area.bounds:\(area.bounds)")
// area.frame:(50.0, 50.0, 200.0, 200.0)
// area.bounds:(0.0, 0.0, 100.0, 100.0)
まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。