1

I'm using this answer to init an ObservableObject with the horizontalSizeClass: https://stackoverflow.com/a/73339015 . What this achieves is to set the blue rectangle to visible on regular sized devices and invisible on compact devices on init. So far so good.

The problem is that the Settings object will of course be re-initalized when the size class changes (for example when rotating an iPhone 13 Pro Max between portrait and landscape). For the user this can result in the blue rectangle appearing or disappearing. What I can't figure out is how I can init isVisible based on the horizontal size class once, but not create a new instance when the horizontal size class changes later to keep the current value of isVisible. Is this even possible?

Code:

struct ContentView: View {
    @Environment(\.horizontalSizeClass) var horizontalSizeClass

    struct MainView: View {
        @EnvironmentObject var settings: Settings

        var body: some View {
            VStack {
                Button("Toggle Visibility") {
                    settings.isVisible.toggle()
                }
                Rectangle()
                    .frame(width: 100, height: 100)
                    .foregroundColor(.blue)
                    .opacity(settings.isVisible ? 1 : 0)
            }
            .animation(.linear(duration: 2.0), value: settings.isVisible)
        }
    }

    var body: some View {
        MainView()
            .environmentObject(
                Settings(isVisible: horizontalSizeClass == .regular)
            )
    }
}

class Settings: ObservableObject {
    @Published var isVisible: Bool

    init(isVisible: Bool) {
        self.isVisible = isVisible
    }
}
3
  • Why not simply use a boolean value for setting, and initialize as a @State object? Commented Aug 20, 2022 at 14:36
  • Do you mean that isVisible should not be changed later on rotation changed (as in example) but keep only one initial value, ie. with different result depending on in which orientation app is launched, right? Commented Aug 20, 2022 at 14:41
  • @Asperi isVisible should init with a specific value depending on the size class, but then it should only be decided by the user if it is visible of not. It should not "automatically" change when the device is rotated. Commented Aug 20, 2022 at 14:48

1 Answer 1

0

isVisible should init with a specific value depending on the size class, but then it should only be decided by the user if it is visible of not. It should not "automatically" change when the device is rotated.

then approach should be different - we will inject state of horizontalSizeClass as initial value and use initializable-once feature of StateObject...

here is main changed parts (tested with Xcode 13.4 / iOS 15.5)

// injection
var body: some View {
    MainView(isVisible: horizontalSizeClass == .regular)
}

// initialisation
struct MainView: View {
    @StateObject var settings: Settings

    init(isVisible: Bool) {
        _settings = StateObject(wrappedValue: Settings(isVisible: isVisible))
    }

everything else is same as before.

Test module is here

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.