SwiftUI Trap change of orientation

The real truth is that I don't know what I am doing. I am trying to trap the change of orientation event. I have been strongly advised to use "Size Classes" rather than "Landscape" or "Portrait". Apparently, this is what Apple recommends.

I have tried two or three ways to do this, and my closest effort to get it working has run me into an Issue (code below) that I don't know how to solve. I believe I have to use the @Evinroment macros to pick up the current size classes (@Environment(\.horizontalSizeClas) var .... and @Environment(\.verticalSizeClass) var ....) and these have to go inside a "View", I think.

But I know when I get to setting up the Notification Center I will have to use the @Published macro to pass the orientation value back to my main "ContentView", again I think. And the @Published macro needs to run in a class. So I have tried to put a "View" inside a "class" and run into an issue that the @Pulished variable (a String) is only recognised in the "class" and the size classes are only recognised in the "View". So How do I overcome this?

Here is the Code I have come up with so far, it is incomplete and when I get this working I will add more.

import SwiftUI

final class OrientChange {
    
    @Published public var myOrient: String
    
    init(myOrient: String){
        self.myOrient = myOrient
    }
    
    struct SizeClassView: View {
        @Environment(\.horizontalSizeClass) var myHorizClass: UserInterfaceSizeClass?
        @Environment(\.verticalSizeClass) var myVertClass: UserInterfaceSizeClass?
        
        var body: some View {
            Text("Horiz Class: \(myHorizClass)")
            if myHorizClass == .compact && myVertClass == .regular {
                OrientChange.myOrient = "Portrait"
            } else {
                Text("No")
            }
        }
    }
}
    
#Preview {
    OrientChange.SizeClassView()
}
Answered by BabyJ in 788779022

I am unsure of what you're trying to accomplish.

Which do you want to do?

  1. Detect when the user rotates their device – in terms of portrait and landscape orientation.
  2. Detect when the physical size of your app changes – in terms of size classes.

Option 1 isn't recommended in cases such as Split View. For example, an iPad may be in landscape orientation but the width of your app isn't the full width of the device, only a portion of it.

Option 2 uses predefined values that tells you whether your app is horizontally (width) or vertically (height) "compact", so you can configure your UI accordingly.


I suggest you have a look at the documentation, especially for SwiftUI. You have some concepts about views, data models and communicating between them incorrect.

Also check out this guide on layout; the "Device size classes" section might give you a better understanding into what "compact" and "regular" size classes mean.

Accepted Answer

I am unsure of what you're trying to accomplish.

Which do you want to do?

  1. Detect when the user rotates their device – in terms of portrait and landscape orientation.
  2. Detect when the physical size of your app changes – in terms of size classes.

Option 1 isn't recommended in cases such as Split View. For example, an iPad may be in landscape orientation but the width of your app isn't the full width of the device, only a portion of it.

Option 2 uses predefined values that tells you whether your app is horizontally (width) or vertically (height) "compact", so you can configure your UI accordingly.


I suggest you have a look at the documentation, especially for SwiftUI. You have some concepts about views, data models and communicating between them incorrect.

Also check out this guide on layout; the "Device size classes" section might give you a better understanding into what "compact" and "regular" size classes mean.

In that case, don't give up so easily. When working with background images you don't really need to worry about device orientation. SwiftUI can let you resize the image and scale it to fill the available space.

Something like this should work:

struct BackgroundImageView: View {
    var body: some View {
        ZStack {
            // Background image
            Image(.background)
                .resizable() // make sure image can be resized
                .scaledToFill() // scale the image so it fills all available space
                .ignoresSafeArea() // [optional] Makes the image fill the whole screen including going behind the clock and battery (top) and the home bar (bottom)

            // Other content goes here
            Text("Main Content")
        }
    }
}
SwiftUI Trap change of orientation
 
 
Q