Oleg Sherman
Oleg Sherman

Reputation: 2802

Using GeometryReader in a ViewModifier doesn't render the view

I have a custom modifier to handle show/hide keyboard, but when running on iOS 13 it doesn't render the view, after some investigation I found that the cause is a usage of GeometryReader in a ViewModifier.

The following code will result in a blank screen:

struct ContentView: View {
    var body: some View {
        Text("Foo")
            .modifier(MyCustomModifier())
    }
}

struct MyCustomModifier: ViewModifier {
    func body(content: Content) -> some View {
        GeometryReader { proxy in
            content
            // Use proxy
        }
    }
}

It happens only for iOS 13 and only if the code is compiled with Xcode 12.

Upvotes: 1

Views: 1256

Answers (2)

user11873221
user11873221

Reputation:

I had the same issue and had to forfeit using ViewModifier altogether and switch to the good old approach with view wrapping in an extension:

extension View {

    /// Conditionally applies bottom padding to the view, if there's no
    /// bottom safe area inset (or if it's less than the padding provided).
    /// - Parameter padding: The min bottom padding to apply.
    @available(iOS, deprecated: 14, message: "Time to switch to the ViewModifier approach.")
    func minBottomPadding(_ padding: CGFloat) -> some View {
        // Currently there's a bug that prevents using GeometryReader inside ViewModifier on iOS 13.
        GeometryReader { geometry in
            self.padding(.bottom, geometry.safeAreaInsets.bottom < padding ? padding : 0)
        }
    }
}

Thank you @oleg-sherman for confirming my suspicions!

Upvotes: 0

Oleg Sherman
Oleg Sherman

Reputation: 2802

It looks like a bug so as a workaround there are two thing that can be done:

1.Use the GeometryReader outside the modifier and pass the proxy to the modifier:

struct ContentView: View {
    var body: some View {
        GeometryReader { proxy in
            Text("Foo")
                .modifier(MyCustomModifier(geometryProxy: proxy))
        }
    }
}

struct MyCustomModifier: ViewModifier {
    let geometryProxy: GeometryProxy
    
    func body(content: Content) -> some View {
        content
        // Use proxy
    }
}

2.Just embed the view that uses the modifier in a GeometryReader:

struct ContentView: View {
    var body: some View {
        GeometryReader { _ in
            Text("Foo")
                .modifier(MyCustomModifier())
        }
    }
}

struct MyCustomModifier: ViewModifier {
    func body(content: Content) -> some View {
        GeometryReader { proxy in
            content
            // Use proxy
        }
    }
}

Upvotes: 3

Related Questions