SwiftUI: Custom .sheet modifier need to attach to top most window of app instead of View

139 Views Asked by At

I am aware about the importance of orders of modifiers in SwiftUI.

SwiftUI provides 2 special modifier interms of .alert(...) & .sheet(...). If these modifiers is attached from any down hierarchy of view, then the result will cover entire view itself.

I am in need of creating a custom sheet modifier (ex: .mobileSheetPresenter($isSheetPresented:...), which should cover entire screen even it is applied anywhere from down view's hierarchy.

The ViewModifier need to attach to Root Window instead of View as the problem shown in below code.

struct MenuView: View {
    
    @State private var isSheetPresented = false
    
    var body: some View {
        VStack {
            VStack { // Yellow View
                Button("Show Mobile Sheet") {
                    isSheetPresented.toggle()
                }
                .mobileSheetPresenter($isSheetPresented) {
                    Text("Hello, MobileSheet! with some long text")
                }
            }
            .frame(width: 300, height: 200)
            .background(.yellow)
            
            VStack { // Red view
                Text("Some Text")
            }
            .frame(width: 300, height: 200)
            .background(.red)
        }
    }
}

As you can see in above code the modifier .mobileSheetPresenter($isSheetPresented) is attached to Button which is bound in a frame of 300X300 with yellow color.

Just below the VStack another view is exist which bound to a frame of 300X200.

When the button trigger presentation of sheet, then the sheet itself is just attached to the Yellow view within frame of 300X300.

Here is the further implementation details


extension View{
    func mobileSheetPresenter<InnerContent : View> (
        _ isSheetPresented: Binding<Bool>,
        @ViewBuilder _ innerContent: @escaping () -> InnerContent
    ) -> some View {
        modifier(MobileSheetPresenter(isPresented: isSheetPresented,
                                      on: innerContent))
    }
}

public struct MobileSheetPresenter<InnerContent: View>: ViewModifier {
    public var isPresented: Binding<Bool>
    public var innerContent: () -> InnerContent
    
    init( isPresented: Binding<Bool>,
          @ViewBuilder on innerContent: @escaping () -> InnerContent
    ) {
        self.isPresented = isPresented
        self.innerContent = innerContent
    }
    
    public func body (content: Content) -> some View {
        content
            .overlay {
                MobileSheet (
                    isPresented: isPresented
                ) {
                    
                    innerContent()
                }
            }
    }
}

Thank you in advance, please let me know incase any further details are required.

0

There are 0 best solutions below