Reputation: 7403
I have a master detail structure with a list on master and a detail page where I want to present a webpage fullscreen, so no navigation bar and no status bar. The user can navigate back by a gesture (internal app).
I'm stuggeling hiding the statusbar with
.statusBar(hidden: true)
This works on master page, but not on detail page.
Hiding the navigation bar works fine with my ViewModifier
public struct NavigationAndStatusBarHider: ViewModifier {
@State var isHidden: Bool = false
public func body(content: Content) -> some View {
content
.navigationBarTitle("")
.navigationBarHidden(isHidden)
.statusBar(hidden: isHidden)
.onAppear {self.isHidden = true}
}
}
extension View {
public func hideNavigationAndStatusBar() -> some View {
modifier(NavigationAndStatusBarHider())
}
}
Any idea?
Upvotes: 4
Views: 1708
Reputation: 118
Solution for Xcode 12.5 and IOS 14.6:
Add the following to your Info.plist
:
<key>UIStatusBarHidden</key>
<true/>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
Add UIApplication.shared.isStatusBarHidden = false
the following to your AppDelegate.swift
:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
UIApplication.shared.isStatusBarHidden = false // -> This
return true
}
You can then hide and bring back the status bar anywhere in the app with the UIApplication.shared.isStatusBarHidden
modifier.
Example:
struct Example: View {
// I'm checking the safe area below the viewport
// to be able to detect iPhone models without a notch.
@State private var bottomSafeArea = UIApplication.shared.windows.first?.safeAreaInsets.bottom
var body: some View {
Button {
if bottomSafeArea == 0 {
UIApplication.shared.isStatusBarHidden = true // or use .toggle()
}
} label: {
Text("Click here for hide status bar!")
.font(.title2)
}
}
}
Upvotes: 1
Reputation: 719
I have a NavigationView
that contains a view that presents a fullScreenModal
. I wanted the status bar visible for the NavigationView
, but hidden for the fullScreenModal
. I tried multiple approaches but couldn't get anything working (it seems lots of people are finding bugs with the status bar and NavigationView
on iOS14).
I've settled on a solution which is hacky but seems to work and should do the job until the bugs are fixed.
Add the following to your Info.plist
:
<key>UIStatusBarHidden</key>
<true/>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
And then add the following in your view's init when necessary (changing true/false as required):
UIApplication.shared.isStatusBarHidden = false
For example:
struct ContentView: View {
init() {
UIApplication.shared.isStatusBarHidden = true
}
var body: some View {
Text("Hello, world!")
}
}
It'll give you a deprecated warning, but I'm hoping this is a temporary fix.
Upvotes: 1
Reputation: 2714
I've been trying this for a couple of hours out of curiosity. At last, I've got it working.
The trick is to hide the status bar in the Main view, whenever the user navigates to the detail view. Here's the code tested in iPhone 11 Pro Max - 13.3 and Xcode version 11.3.1. Hope you like it ;). Happy coding.
import SwiftUI
import UIKit
import WebKit
struct ContentView: View {
var urls: [String] = ["https://www.stackoverflow.com", "https://www.yahoo.com"]
@State private var hideStatusBar = false
var body: some View {
NavigationView {
List {
ForEach(urls, id: \.self) { url in
VStack {
NavigationLink(destination: DetailView(url: url)) {
Text(url)
}
.onDisappear() {
self.hideStatusBar = true
}
.onAppear() {
self.hideStatusBar = false
}
}
}
}
.navigationBarTitle("Main")
}
.statusBar(hidden: hideStatusBar)
}
}
struct DetailView: View {
@Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
var url: String = ""
var body: some View {
VStack {
Webview(url: url)
Button("Tap to go back.") {
self.presentationMode.wrappedValue.dismiss()
}
Spacer()
}
.hideNavigationAndStatusBar()
}
}
public struct NavigationAndStatusBarHider: ViewModifier {
@State var isHidden: Bool = false
public func body(content: Content) -> some View {
content
.navigationBarTitle("")
.navigationBarHidden(isHidden)
.statusBar(hidden: isHidden)
.onAppear {self.isHidden = true}
}
}
struct Webview: UIViewRepresentable {
var url: String
typealias UIViewType = WKWebView
func makeUIView(context: UIViewRepresentableContext<Webview>) -> WKWebView {
let wkWebView = WKWebView()
guard let url = URL(string: self.url) else {
return wkWebView
}
let request = URLRequest(url: url)
wkWebView.load(request)
return wkWebView
}
func updateUIView(_ uiView: WKWebView, context: UIViewRepresentableContext<Webview>) {
}
}
extension View {
public func hideNavigationAndStatusBar() -> some View {
modifier(NavigationAndStatusBarHider())
}
}
Upvotes: 6
Reputation: 257711
Well, your observed behaviour is because status bar hiding does not work being called from inside NavigationView
, but works outside. Tested with Xcode 11.2 and(!) Xcode 11.4beta3.
Please see below my findings.
Case1 Case2
Case1: Inside any stack container
struct TestNavigationWithStatusBar: View {
var body: some View {
VStack {
Text("Hello, World!")
.statusBar(hidden: true)
}
}
}
Case2: Inside NavigationView
struct TestNavigationWithStatusBar: View {
var body: some View {
NavigationView {
Text("Hello, World!")
.statusBar(hidden: true)
}
}
}
The solution (fix/workaround) to use .statusBar(hidden:)
outside of navigation view. Thus you should update your modifier correspondingly (or rethink design to separate it).
struct TestNavigationWithStatusBar: View {
var body: some View {
NavigationView {
Text("Hello, World!")
}
.statusBar(hidden: true)
}
}
Upvotes: 2