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.
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?