1

I'm targeting iOS 16 for my app in which I access the screen height and width using UIScreen.main.bounds.width and UIScreen.main.bounds.height so I can draw views based on these two values. I'm assigning these two values to two CGFloat properties in the view struct as follows:

struct ContentView: View {
var width: CGFloat = UIScreen.main.bounds.width
var height: CGFloat = UIScreen.main.bounds.height
var fontSize: CGFloat
var body: some View {
    // draw views here using width and height properties

 }

Xcode is showing a warning message saying 'main' will be deprecated in a future version of iOS: use a UIScreen instance found through context instead: i.e, view.window.windowScene.screen

I'm not sure how to apply the answer here to my use case and I don't want to use GeometryReader since it just messes up the overall layout.

Any suggestions on how to obtain screen width and height in an app targeting iOS 16 and above without using GeometryReader?

Dávid Pásztor
  • 51,403
  • 9
  • 85
  • 116
abs8090
  • 111
  • 2
  • 9
  • Use `GeometryReader` with a `PreferenceKey` -- it doesn't have to affect your layout. https://www.fivestars.blog/articles/swiftui-share-layout-information/ – jnpdx Feb 07 '23 at 16:02
  • 1
    SwiftUI.Layout is the alternative. It is very easy to use. – lorem ipsum Feb 07 '23 at 16:06
  • 1
    One of the essentials (and benefits) of SwiftUI to ***declare*** views regardless of the screen size – vadian Feb 07 '23 at 16:12
  • can you please share a link that explains how to use SwiftUI.Layout? thanks for your answer @Iorem – abs8090 Feb 07 '23 at 16:12
  • thanks @vadin, but I need to give child views size relative to the screen size. Any suggestions please? – abs8090 Feb 07 '23 at 16:19
  • 1
    @abs8090 you shouldn't use the screen size for sizing any views. You should use the __window__ size, since on iPad your app might be used in a split view and hence the screen size is meaningless, because your app might not take up the whole screen. Just get the size of a `GeometryReader` from a view which is taking up the whole window and propagate that down to any smaller child views. – Dávid Pásztor Feb 07 '23 at 16:23
  • 2
    You should explain in the question what exactly are you going to accomplish. – vadian Feb 07 '23 at 16:23
  • 1
    https://developer.apple.com/wwdc22/10056 – lorem ipsum Feb 07 '23 at 17:40

2 Answers2

1

Swift 5.5

@main
struct MyApp: App {
    var body: some Scene {
        WindowGroup {
            GeometryReader { proxy in
                ContentView()
                    .environment(\.mainWindowSize, proxy.size)
            }
        }
    }
}

struct ContentView: View {   
    
    @Environment(\.mainWindowSize) var windowSize
    
    var body: some View {
        ZStack {
            Text("Hello, world!")
                .frame(width: windowSize.width/2, height: windowSize.height)
                .background(Color.blue)
        }
    }
}

private struct MainWindowSizeKey: EnvironmentKey {
    static let defaultValue: CGSize = .zero
}

extension EnvironmentValues {
    var mainWindowSize: CGSize {
        get { self[MainWindowSizeKey.self] }
        set { self[MainWindowSizeKey.self] = newValue }
    }
}

image_example

MaatheusGois
  • 139
  • 5
  • That would be terribly inefficient as it would redraw the entire app many times. Just use an “onChange” to see how many times the proxy changes. As you use the app. – lorem ipsum Feb 07 '23 at 18:22
-2

There is a new feature in iOS 16: Users can duplicate an application. So it looks like the user has five applications, but only one is actually running. When that happens, things like UIScreen.main don't make sense anymore, because you are actually responsible for five apps!

Now if you have a view, that belongs to ONE of the five virtual apps, so view.window.windowScene.screen will be the UIScreen that is actually responsible for what the user sees (not the four other instances of the app in the background). In iOS 17, code like that will be deprecated. State that used to be global in iOS 15 isn't global anymore.

Take an extreme case: Two copies of an app, both running in split screen, one on the left third, one on the right two thirds of your screen. There is nothing "global" that you could use.

gnasher729
  • 51,477
  • 5
  • 75
  • 98