Sponsor Link
環境&対象
- macOS14.3 Beta
- Xcode 15.2 beta
- iOS 17.2
- Swift 5.9
ProposedViewSize
iOS16/macOS13 以降で提供されている View のサイズに関する情報の struct です。
Apple のドキュメントは、こちら。
ProposedViewSize は、View のサイズ指定に使用される struct なので width・height データで構成されています。
使われるシーン
ProposedViewSize は、以下の API の引数として渡されてきます。
・Layout の sizeThatFits, placeSubviews
・NSViewRepresentable/UIViewRepresentable の sizeThatFits
Layout では、親 View からのサイズ問い合わせ時に、親 View から与えられる情報の1つです。
NSViewRepresentable/UIViewRepresentable では、自身の View のサイズを 返す sizeThatFits が呼び出される時の1つの引数であり、呼び出し側(親 View)から与えられる情報の1つです。
width,height指定での生成
一番ベタ(?)な使い方は、以下のように width・height を指定することです。
let newSize = ProposedViewSize(width: 240, height: 160)
width/height の型は、Optional<CGFloat> ですので、それぞれについて nil を設定することも、CGFloat.infinity を設定することもできます。
nil が設定されているときには、”指定値がない” ことを意味します。つまり、”自身にとって理想的なスペースを使うような要求” を意味します。
CGFloat.infinity が設定されているときには、”最大限のスペースを使うような要求” を意味します。
値として “0” が設定されているときは、”最小限のスペースを使うような要求” を意味します。
width/height それぞれに指定可能ですので、以下のような指定も可能です。
let unspecifiedWidthMaxHeight = ProposedViewSize(width: nil, height: CGFloat.infinity)
let minimumWidthHeight = ProposedViewSize(width: 0, height: 0)
1つめの要求の意味は、幅方向は指定をしない/高さ方向は最大限に使用して良い ということになります。
2つめの要求の意味は、幅方向/高さ方向どちらも最小限のスペースを使用する ということになります。
あくまで 親 View からの要求情報であり、かならずしも 整合されたレイアウトになることは保証されません。
static で定義されているデータ
よく使用されるデータが static として以下のように定義されています。
- zero
- 幅・高さ ともに、0
- infinity
- 幅・高さ ともに infinity
- unspecified
- 幅・高さともに 未指定
以下では、それぞれのケースで具体的に設定されている値を確認してみます。
zero
以下のように、width, height ともに、0 が設定されています。つまり 可能な限り小さいサイズを要求していることになります。
print(ProposedViewSize.zero)
// print-out
ProposedViewSize(width: Optional(0.0), height: Optional(0.0))
infinity
以下のように、width, height ともに、CGFloat.infinity が設定されています。
print(ProposedViewSize.infinity)
// print-out
ProposedViewSize(width: Optional(inf), height: Optional(inf))
print(ProposedViewSize.infinity.width == CGFloat.infinity)
// print-out
true
unspecified
以下のように、width, height ともに、nil が設定されています。
先にも確認しましたが、width/height の型は いずれも Optional<CGFloat> ですので、このような値も持ちえます。
print(ProposedViewSize.unspecified)
// print-out
ProposedViewSize(width: nil, height: nil)
便利なメソッド
非常にシンプルな ProposedViewSize 型ですが、計算するときに便利になるようなメソッドが定義されています。
先に見たように ProposedViewSize の width/height は、数値を持つ場合の他に (無指定を意味する) nil を持つことがあります。
仕様としてはわかりますが、実際に ProposedViewSize の値を利用して サイズ計算をしようとすると、nil の場合をきちんと処理しないといけないため、コードが煩雑になりがちです。
そのようなときに、適当(?)に 実数値を持つ CGSize を返してくれるメソッドが用意されています。
replacingUnspecifiedDimensions(by:)
引数に、CGSize を与えることで、nil が指定されている width / height を置き換えて、CGSize を返してくれます。
以下のように nil が指定されている width/height について、引数として与えた値を使用した CGSize になります。
let unspecified = ProposedViewSize.unspecified
let widthUnspecified = ProposedViewSize(width: nil, height: 100)
let widthInfinity = ProposedViewSize(width: .infinity, height: 100)
let heightUnspecified = ProposedViewSize(width: 100, height: nil)
let heightInfinity = ProposedViewSize(width: 100, height: .infinity)
let specified = ProposedViewSize(width: 100, height: 100)
let refSize = CGSize(width: 200, height: 200)
print(unspecified.replacingUnspecifiedDimensions(by: refSize))
// (200.0, 200.0) refSize そのまま採用
print(widthUnspecified.replacingUnspecifiedDimensions(by: refSize))
// (200.0, 100.0) refSize の width のみ採用
print(widthInfinity.replacingUnspecifiedDimensions(by: refSize))
// (inf, 100.0) refSize は無視される(inf はそのまま)
print(heightUnspecified.replacingUnspecifiedDimensions(by: refSize))
// (100.0, 200.0) refSize の height のみ採用
print(heightInfinity.replacingUnspecifiedDimensions(by: refSize))
// (100.0, inf) refSize は無視される(inf はそのまま)
print(specified.replacingUnspecifiedDimensions(by: refSize))
// (100.0, 100.0) refSize は 無視される
なお、引数を省略すると、CGSize(width: 10, height: 10) なる CGSize が与えられたものとして処理されます。
print(unspecified.replacingUnspecifiedDimensions())
// (10.0, 10.0)
print(widthUnspecified.replacingUnspecifiedDimensions())
// (10.0, 100.0)
print(widthInfinity.replacingUnspecifiedDimensions())
// (inf, 100.0)
print(heightUnspecified.replacingUnspecifiedDimensions())
// (100.0, 10.0)
print(heightInfinity.replacingUnspecifiedDimensions())
// (100.0, inf)
print(specified.replacingUnspecifiedDimensions())
// (100.0, 100.0)
あくまで、nil を置き換えてくれるだけです。
.infinity は .infinity のままです。
まとめ
ProposedViewSize は、View の Size を指定するために用意された struct
- width と height の情報を Optional<CGFloat> で持つ struct
- width/height は、.infinity を持つことがあり、最大限のスペースを使うような要求を意味する
- width/height は、nil を持つことがあり、理想的なスペースを使うような要求を意味する
- width/height は、0 を持つことがあり、最小限のスペースを使うような要求を意味する
説明は以上です。
不明な点やおかしな点ありましたら、こちらまで。
SwiftUI おすすめ本
SwiftUI を理解するには、以下の本がおすすめです。
SwiftUI ViewMatery
SwiftUI で開発していくときに、ViewやLayoutのための適切なmodifierを探すのが大変です。
英語での説明になってしまいますが、以下の”SwiftUI Views Mastery Bundle”という本がビジュアル的に確認して探せるので、便利です。
英語ではありますが、1ページに コードと画面が並んでいるので、非常にわかりやすいです。
View に適用できる modifier もわかりやすく説明されているので、ビューの理解だけではなく、どのような装飾ができるかも簡単にわかります。
超便利です
販売元のページは、こちらです。
SwiftUI 徹底入門
# SwiftUI は、毎年大きく改善されていますので、少し古くなってしまいましたが、いまでも 定番本です。
Swift学習におすすめの本
詳解Swift
Swift の学習には、詳解 Swift という書籍が、おすすめです。
著者は、Swift の初期から書籍を出していますし、Swift の前に主力言語だった Objective-C という言語についても同様の書籍を出しています。
最新版を購入するのがおすすめです。
現時点では、上記の Swift 5 に対応した第5版が最新版です。
Sponsor Link