Portrait

I2H3

Notes from work as an app developer for iPhones, iPads and Macs.

RSS Icon GitHub Mastodon

SwiftUI Platform-Dependent Padding Modifier

Some SwiftUI views I have require padding one platform and none on the other. To avoid preprocessor switches everywhere I created a custom view modifier for it.

I am still not really convinced that SwiftUI is that great. I do not get the excitement. To me, it is too constrained and cumbersome. I have enjoyed the freedom of the web technologies from vanilla CSS to single-page applications with Vue.js and Vuex (not en vogue anymore by now). Whenever you try to get off the happy path, it will turn into pain nowhere as fast as in SwiftUI. At least on macOS and when you try to maintain a multi-platform user interface. Dusty AppKit still appears superior to me and I think storyboards just should have gotten more love.

a memoji

Anyway, here is the code. A simple enum to have a safe way to tell the modifier which platform it should be effective on. And a switch statement combined with preprocessor switches.

struct PlatformPadding: ViewModifier {
    let edges: Edge.Set
    let length: CGFloat?
    let platform: Platform

    init(_ platform: Platform, _ edges: Edge.Set = .all, _ length: CGFloat? = nil) {
        self.edges = edges
        self.length = length
        self.platform = platform
    }

    func body(content: Content) -> some View {
        switch platform {
            case .iOS:
                #if os(iOS)
                    content.padding(edges, length)
                #else
                    content
                #endif
            case .macOS:
                #if os(macOS)
                    content.padding(edges, length)
                #else
                    content
                #endif
        }
    }
}

To not always have to call .modifier(PlatformPadding(.macOS)), I created an extension on View.

extension View {
    func platformPadding(_ platform: Platform, _ edges: Edge.Set = .all, _ length: CGFloat? = nil) -> some View {
        modifier(PlatformPadding(platform, edges, length))
    }
}

And finally, this is all to apply it on a view:

Form {
    // View code here.
}
.platformPadding(.macOS)