Make SwiftUI child view fill entire screen on tap, with all code encapsulated in child view

I have a simple SwiftUI ButtonView that contains a button. I would like the ButtonView to fill the entire screen of the device when tapped. However I would like that all the code to perform the filling of the screen remains encapsulated within the ButtonView, so any SwiftUI view that incorporates the ButtonView can use it to fill the screen. My attempt at doing this causes the ButtonView to not fill the entire screen because it is aligned incorrectly by its parent view despite being of the screen frame size. Here is some code I wrote to attempt this.

import SwiftUI

struct ContentView: View {
  var body: some View {
    VStack {
      ButtonView()
      Text("Some text that shouldn't be visible in fullscreen")
        .foregroundColor(Color.black)
        .padding()
        .background(Color.yellow)
    }
  }
}

struct ButtonView: View {
  @State var isFullscreen = false
  
  func getFrameWidth() -> CGFloat? {
    if self.isFullscreen {
      return CGFloat(UIApplication.shared.windows.first!.frame.width)
    } else {
      return nil
    }
  }
  
  func getFrameHeight() -> CGFloat? {
    if self.isFullscreen {
      return CGFloat(UIApplication.shared.windows.first!.frame.height)
    } else {
      return nil
    }
  }
  
  var body: some View {
    
    let width = getFrameWidth()
    let height = getFrameHeight()
    
    let widthStr = width != nil ? width!.description : "default"
    let heightStr = height != nil ? height!.description : "default"
    
    return Button("WIDTH: \(widthStr), HEIGHT: \(heightStr)") {
      self.isFullscreen.toggle()
    }
    .frame(width: width, height: height, alignment: .center)
    .foregroundColor(Color.primary)
    .background(Color.gray)
    .animation(.easeIn)
  }
}

struct ContentView_Previews: PreviewProvider {
  static var previews: some View {
    ContentView()
  }
}

My approach was to use a @State var isFullscreen to keep track of whether the button is in full screen or not. Then I use the frame modifier and in it makes calls to functions to get the frame widths and heights. The widths and heights return nil when the button is not in fullscreen, so the frame modifier simply lays out the buttons text and adopts the size of the text it contains. When the button is full screen however, the functions return UIApplication.shared.windows.first!.frame.width And UIApplication.shared.windows.first!.frame.height respectively. Using this approach the ButtonView is takes the size of the screen. However the problem that arises is that if the parent contains any other sub views as siblings of the ButtonView these affect the alignment of the ButtonView itself. In this case the Text("Some text that shouldn't be visible in fullscreen") ends up taking up some amount of space at the bottom of the screen, I presume because the RootView is centring the VStack that contains the ButtonView() and the Text() horizontally within it when the VStack takes up more space than is available on the screen.
Ideally these siblings should be hidden or at least completely pushed out of the visible area.

Clicking the button gives it the right frame dimensions, but it is not  correctly aligned

A pure SwiftUI solution I thought of might use a @State boolean variable called fullscreen in the ContentView() and pass in some closures to the ButtonView that toggle the parent's fullscreen state when it is clicked. However this means that I am not encapsulating all the functionality of fullscreen into the ButtonView. Whoever uses the ButtonView() must now manually ensure that all other views except the ButtonView() in the view hierarchy are conditionally displayed only when that state variable is false.

Is there a way for me to do this in SwiftUI OR alternatively in UIKit, while encapsulating all the code to make the app go fullscreen in the ButtonView() so that the it takes up the entire space of the screen, and any of its sibling views are hidden or at least pushed out of the visible screen?

In the future when it is possible to customize transition animations, you would be able to use this:
(or maybe even today if you don't care about the fact that the view slides from the right)

struct ContentView: View {
    var body: some View {
        NavigationView {
            VStack {
                ButtonView()
                Text("Some text that shouldn't be visible in fullscreen")
                    .foregroundColor(Color.black)
                    .padding()
                    .background(Color.yellow)
            }
        }
    }
}

struct ButtonView: View {
    @State var isFullscreen = false

    var body: some View {
        VStack {
            NavigationLink(
                destination: self.content.navigationBarHidden(true),
                isActive: $isFullscreen) {
                EmptyView()
            }
            self.content
        }
    }

    var content: some View {
        Button("Some width and some height") {
            self.isFullscreen.toggle()
        }
        .foregroundColor(Color.primary)
        .background(Color.gray)

    }
}

Ahh I really wanted it to expand into fullscreen, kind of like how an AVPlayer would.

Terms of Service

Privacy Policy

Cookie Policy