skip to Main Content

I put a WebView inside my app, as you can see from the image everything works fine on iPhones with the notch (I tried on both iOS 15 and 16), while on the new 14 Pro and Pro Max there is a white line that appears between the end of the status bar and the beginning of the WebView. I thought it might be a bug in the Simulator, but i’m not so sure… Is there some way to hide that line without messing with the other devices?

Here is the code I’m using for the WebView and for the specific tab:

import Foundation
import SwiftUI
import WebKit

struct WebView: UIViewRepresentable {
    
    let url: URL
    
    func makeUIView(context: Context) -> some UIView {
        let webView = WKWebView()
        let request = URLRequest(url: url)
        webView.load(request)
        return webView
    }
    
    func updateUIView(_ uiView: UIViewType, context: Context) {
        
    }
}

struct SearchView: View {
    
    let sysLanguage = NSLocale.current.languageCode
    
    var body: some View {
        if sysLanguage == "it" {
            WebView(url: URL(string: "https://www.vivibusso.app/webapp_test/it/search.html")!)
                .navigationBarHidden(true)
        } else {
            WebView(url: URL(string: "https://www.vivibusso.app/webapp_test/it/search.html")!)
                .navigationBarHidden(true)
        }
    }
}

struct SearchView_Previews: PreviewProvider {
    static var previews: some View {
        SearchView()
    }
}

Here’s the code for the ContentView:

import SwiftUI
import UIKit

struct ContentView: View {
    
    @State private var selected = 0
    
    var body: some View {
        TabView(selection: $selected) {
            NavigationView {
                HomeView()
            }
            .navigationViewStyle(StackNavigationViewStyle())
            .tabItem {
                Image(systemName: (selected == 0 ? "house.fill" : "house"))
                Text("Home")
            }.tag(0)
            NavigationView {
                CategoryView()
            }
            .navigationViewStyle(DoubleColumnNavigationViewStyle())
            .tabItem {
                Image(systemName: (selected == 1 ? "text.justify" : "text.justify"))
                Text("Categorie")
            }.tag(1)
            NavigationView {
                GalleryView()
            }
            .edgesIgnoringSafeArea(.all)
            .navigationViewStyle(StackNavigationViewStyle())
            .tabItem {
                Image(systemName: (selected == 2 ? "photo.fill" : "photo"))
                Text("Galleria")
            }.tag(2)
            NavigationView {
                SearchView()
            }
            .edgesIgnoringSafeArea(.all)
            .navigationViewStyle(StackNavigationViewStyle())
            .tabItem {
                Image(systemName: (selected == 3 ? "magnifyingglass" : "magnifyingglass"))
                Text("Ricerca")
            }.tag(3)
        }
        .accentColor(.white)
        .onAppear() {
            UITabBar.appearance().barTintColor = UIColor(red: 125.0/255.0, green: 102.0/255.0, blue: 159.0/255.0, alpha: 1.0)
            UITabBar.appearance().backgroundColor = UIColor(red: 125.0/255.0, green: 102.0/255.0, blue: 159.0/255.0, alpha: 1.0)
            UITabBar.appearance().unselectedItemTintColor = UIColor(red: 200.0/255.0, green: 200.0/255.0, blue: 200.0/255.0, alpha: 1.0)
        }
    }
}

extension UINavigationController {
    override open func viewDidLoad() {
        super.viewDidLoad()
        let app = UIApplication.shared.connectedScenes.first as? UIWindowScene
        let statusBarHeight = app?.statusBarManager?.statusBarFrame.height ?? 0
        let statusbarView = UIView()
        statusbarView.backgroundColor = UIColor(red: 125.0/255.0, green: 102.0/255.0, blue: 159.0/255.0, alpha: 1.0)
        view.addSubview(statusbarView)
        statusbarView.translatesAutoresizingMaskIntoConstraints = false
        statusbarView.heightAnchor
            .constraint(equalToConstant: statusBarHeight).isActive = true
        statusbarView.widthAnchor
            .constraint(equalTo: view.widthAnchor, multiplier: 1.0).isActive = true
        statusbarView.topAnchor
            .constraint(equalTo: view.topAnchor).isActive = true
        statusbarView.centerXAnchor
            .constraint(equalTo: view.centerXAnchor).isActive = true
        let appearanceNav = UINavigationBarAppearance()
        appearanceNav.backgroundColor = UIColor(red: 125.0/255.0, green: 102.0/255.0, blue: 159.0/255.0, alpha: 1.0)
        appearanceNav.largeTitleTextAttributes.updateValue(UIColor.white, forKey: NSAttributedString.Key.foregroundColor)
        appearanceNav.titleTextAttributes.updateValue(UIColor.white, forKey: NSAttributedString.Key.foregroundColor)
        appearanceNav.shadowColor = nil
        navigationBar.standardAppearance = appearanceNav
        navigationBar.compactAppearance = appearanceNav
        navigationBar.scrollEdgeAppearance = appearanceNav
        navigationBar.tintColor = UIColor.white
    }
}

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

1

Thank you!

2

Answers


  1. Update: This only works for iOS 15 and above (I’m currently using iOS 16)

    I found that offsetting a view below the top of the safe area causes its background color to extend to the top of the screen. Then you don’t have to wrap your tab view items in navigation views, and can get rid of the UINavigationController extension. See the last two lines in my version of your code, below.

    I’m not exactly sure why this works. Potentially, it’s exploiting a bug in SwiftUI, and the behavior could change in the future.

    struct ContentView: View {
        
        @State private var selected = 0
        
        var body: some View {
            TabView(selection: $selected) {
                Text("Home View")
                    .tabItem {
                        Image(systemName: (selected == 0 ? "house.fill" : "house"))
                        Text("Home")
                    }.tag(0)
                
                Text("Category View")
                    .tabItem {
                        Image(systemName: (selected == 1 ? "text.justify" : "text.justify"))
                        Text("Categorie")
                    }.tag(1)
                
                Text("Gallery View")
                    .tabItem {
                        Image(systemName: (selected == 2 ? "photo.fill" : "photo"))
                        Text("Galleria")
                    }.tag(2)
                
                SearchView()
                    .tabItem {
                        Image(systemName: (selected == 3 ? "magnifyingglass" : "magnifyingglass"))
                        Text("Ricerca")
                    }.tag(3)
            }
            .accentColor(.white)
            .onAppear() {
                UITabBar.appearance().barTintColor = UIColor(red: 125.0/255.0, green: 102.0/255.0, blue: 159.0/255.0, alpha: 1.0)
                UITabBar.appearance().backgroundColor = UIColor(red: 125.0/255.0, green: 102.0/255.0, blue: 159.0/255.0, alpha: 1.0)
                UITabBar.appearance().unselectedItemTintColor = UIColor(red: 200.0/255.0, green: 200.0/255.0, blue: 200.0/255.0, alpha: 1.0)
            }
            .offset(CGSize(width: 0, height: 1)) // move TabView down one point
            .background(Color(red: 125.0/255.0, green: 102.0/255.0, blue: 159.0/255.0))
        }
    }
    

    TabView with colored unsafe area

    Login or Signup to reply.
  2. heightAnchor, topAnchor, and centerXAnchor may be in conflict with each other. Just use widthAnchor, topAnchor, and bottomAnchor.

    statusbarView.widthAnchor
        .constraint(equalTo: view.widthAnchor).isActive = true
    statusbarView.topAnchor
        .constraint(equalTo: view.topAnchor).isActive = true
    statusbarView.bottomAnchor
        .constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search