7
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

[SwiftUI] 画面の幅、高さを取得する方法

Last updated at Posted at 2022-08-17

概要

タイトルの通り、SwiftUI で、画面の幅と高さを取得する方法についての記事です。
なお、「いや、UIScreen.main.bounds で取得できるやろ、何言っとるんやお前」と思われた方もいらっしゃると思いますが、UIScreen.main.bounds だと、iPadOS で SplitView した際などに画面幅の変更が反映されないため、本記事を書きました。

ざっくりとした実装方針

  1. 画面サイズをグローバルで保存するため、ObservableObject に準拠したクラスを作成
  2. ContentView で、子 View を GeometryReader でラップ
  3. .onChange モディファイアを使って、GeometryReader を使って取得した画面サイズを1. で作成したストアに保存

1. 画面サイズを保存するクラスを作成

ObservableObject に準拠した、画面サイズを保存するクラスを作成します。 update 関数を作ったのは、使用側で ScreenSizeStore を書き換えるような書き方をしたくなかったのが理由です。

ScreenSizeStore.swift
import Foundation
import Combine
import SwiftUI

final class ScreenSizeStore: ObservableObject {
    @Published private(set) var screenWidth: CGFloat
    @Published private(set) var screenHeight: CGFloat
   
    // 一旦デフォルトの画面サイズで初期化
    init() {
        self.screenWidth = UIScreen.main.bounds.width
        self.screenHeight = UIScreen.main.bounds.height
    }
    
    func update(width: CGFloat, height: CGFloat) {
        self.screenWidth = width
        self.screenHeight = height
    }
}

2. ContentView に GeometryReader 設置

ContentView に、GeometryReader を設置します。ContentView の親となる App に置くと色々面倒そうだと思ったので、ContentView にしています。

ContentView.swift
import SwiftUI

struct ContentView: View {
    var body: some View {
        GeometryReader { rootViewGeometry in
          // 子 View
          HogeView()
        }
    }
}

3. .onChange を使い、ScreenSizeStore を更新

ContentView に、@EnvironmentObject の宣言の設置と、子 View への .onChange モディファイアの追加を行います。

ContentView.swift
import SwiftUI

struct ContentView: View {
    @EnvironmentObject var screenSizeStore: ScreenSizeStore
    
    var body: some View {
        GeometryReader { rootViewGeometry in
            RootView()
                .onAppear {
                    screenSizeStore.update(width: rootViewGeometry.size.width, height: rootViewGeometry.size.height)
                }
                .onChange(of: rootViewGeometry.size) { updatedValue in
                    screenSizeStore.update(width: updatedValue.width, height: updatedValue.height)
                }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
            .environmentObject(ScreenSizeStore())
    }
}

最後に、App 側で、ContentView.environmentObject モディファイアを追加する必要があります。(追加しないとエラーが出る)

Hoge_App.swift
import SwiftUI

@main
struct Hoge_App: App {
    var body: some Scene {
        WindowGroup {
          ContentView()
              .environmentObject(ScreenSizeStore())
        }
    }
}

使用例

使用側は、@EnvironmentObject の宣言を追加してやるだけです

CousinView.swift
import SwiftUI

struct CousinView: View {
    @EnvironmentObject var screenSizeStore: ScreenSizeStore

    var body: some View {
        VStack {
            HStack {
              (中略)

            }
            .frame(maxWidth: screenSizeStore.width)
        }
    }
}

最後に

いかがでしょうか?
もし、「もうちょっといいやり方あるぞ」などのご意見あれば、お気軽にコメント欄に投稿していただければ幸いです。

7
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?