👽

【Swift UI】UIScreen.mainが非推奨 対処法と解説 GeometryReaderについても

2024/01/04に公開

UIScreen.mainを使わない画面幅の取得とmainの解説

UIScreen.mainとは

mainは、class var main: UIScreen { get }と定義されており、デバイスの画面を表すオブジェクトを返します。
なので、UIScreen.main.bounds.widthを使って画面幅を取得できました。
ちなみに、boundsを日本語で枠という意味です。
Swiftの世界でのboundsは、自身を基準とした座標とサイズを返したり指定したりできます。

var bounds: CGRect { get set }

自身が座標の基準なので、デフォルトでは(x:0,y:0)です。サイズはframeと同じ長方形のサイズです。

そういうわけで、UIScreen.main.bounds.widthはデバイスの画面オブジェクトの枠の横幅、つまりwidthを取得している。
しかし、今回非推奨になりました。

対処法

.connectedScenesを使う

.connectedScenesとは、アプリが今接続しているsceneを返すプロパティです。
具体的には、動作している可能性があるsceneを位置に限らず返します。位置に限らずとは前画面にあるか背景にあるか画面外にあるかに限らずという意味です。

let window = UIApplication.shared.connectedScenes.first as? UIWindowScene 
window.screen.bounds.width

となる。

コード 見た目

このような形で幅を取得できる。

弱点

.connectedScenesには、複数のUIWindowSceneが入っている可能性があります。なので、欲しいwindowがfirstで取得できるかわかりません。

GeometryReaderを使う

GeometryReaderとは、コンテンツ独自のサイズと座標を返してくるstruck(構造体)です。
簡単に説明すると親ビューのレイアウト情報を返します。

コード 見た目
        GeometryReader {
            geome in
            Text("横幅\(geome.size.width)")
        }

解説

今回GeometryReaderで取得した幅が、mainを使って取得した画面幅と同じ393になっていることがわかります。つまり、親ビューであるzennViewのbodyのサイズをGeometryReaderで取得しています。

わかりやすい画像を貼ります。

コード 見た目

上記画像では、親ビュー(zennViewのbody)にsubViewを作り、GeometryReaderがあるsceneWidthをsubViewに配置しました。
GeometryReaderがあるsceneWidthから見るとsubViewが親ビューになっているので、幅が200となっています。

要約

GeometryReaderは親ビューのサイズを取得する。

弱点

1.複数の横幅を取得するときにネストが深くなり、可読性が低下する。
2.上記画像でもわかるように何もしてないのにViewの位置が中心じゃなくなっている。
2に関しては、paddingとかで何とかなりそう。

コード 見た目

番外編 GeometryReaderの高さ

高さも幅と同じように取得できるのですが、下記コードのようにすることでセーフエリアも含めて取得できます。

       GeometryReader {
           geome in
           Text("横幅\(geome.size.height)")
        }
        .ignoresSafeArea()

Viewから取得する。

SwiftUIではできませんので割愛しますが、

        view.window?.windowScene?.windows.first?.screen.bounds.width

もしくは

        view.window?.screen.bounds.width

この二つのどちらかでも画面幅は取得可能なようです。
しかし、こちらは対象のviewが表示されるまで取得できないので、最速でもviewDidAppearで取得ですね〜

Discussion