2

I'm working on a cross-platform app using SwiftUI. I have a view that consists of an HStack with various items lined up in it. In essence, this:

struct ContentView: View {
    var body: some View {
        HStack {
            // Some stuff on the left side of this HStack
            Spacer()
            // more stuff on the right side
        }
    }
}

The Spacer takes up as much space as it can, which pushes the views before it to the left side and views after it to the right side of the row. I've got it to a point where this looks great on iOS.

On macOS though, my window width is much larger and can further be resized by the user. At those larger widths it starts to get awkward to see the row content separated by so much space. So I'd like to limit the width. Essentially, I want to do this:

struct ContentView: View {
    var body: some View {
        HStack {
            // a bunch of stuff in this stack
        }
        #if os(macOS)
        .frame(width: 120)
        #endif
    }
}

But that gets me the error "Unexpected platform condition (expected 'os', 'arch', or 'swift')" coming from the line with the .frame modifier. If I recreate the entire HStack inside the platform check, as given below, everything works.

struct ContentView: View {
    var body: some View {
        #if os(iOS)
        HStack {
            // a bunch of stuff in this stack
        }
        #elseif os(macOS)
        HStack {
            // a bunch of stuff in this stack
        }
        .frame(width: 120)
        #endif
    }
}

But it seems very error prone to replicate everything inside the HStack, just to be able to vary the modifier based on platform. Is there really no way to conditionally compile just modifier code?

Cem Schemel
  • 442
  • 3
  • 13

2 Answers2

1

Just separate bunch of stuff into standalone view, like

struct ContentView: View {
    var body: some View {
        #if os(iOS)
          MainView()
        #elseif os(macOS)
          MainView()
             .frame(width: 120)
        #endif
    }
}

struct MainView: View {
    var body: some View {
        HStack {
            // a bunch of stuff in this stack
        }
    }
}
Asperi
  • 228,894
  • 20
  • 464
  • 690
0

More elegant, appropriate and reusable approach to conditionally add modifier would be by using EmptyModifier().

We can use the empty modifier to switch modifiers at compile time during development.

Let's say you want apply frame modifier based on OS Conditions, First create a custom ViewModifier like so:

struct CustomFrame: ViewModifier {
    func body(content: Content) -> some View {
            content
            .frame(width: 120)
        }
}

Now create an instance of CustomFrame ViewModifier and add conditions as per the business logic:

struct ContentView: View {
    
    var frameModifier: some ViewModifier {
        #if os(iOS)
        return CustomFrame()
        #elseif os(macOS)
        return EmptyModifier() // <- EmptyModifier()
        #endif
    }
    
    var body: some View {
        HStack {
            // a bunch of stuff in this stack
        }
        .modifier(frameModifier)  // <- Use custom modifiers like this.
    }
}

This will let you add modifiers conditionally to any view in Swifty way.

Kush Bhavsar
  • 909
  • 2
  • 12