SwiftUI - TabView with NavigationView generates gray area - swift

I have some problems with my tabbed view when I set isTranslucent to false in combination with a NavigationView.
Does anyone know how to fix this? The problem is shown in the attached image.
I need translucent set to false otherwise I can't get the dark color.

You can set backgroundColor. Don't set isTranslucent to false or it will create these artefacts you mentioned.
UITabBar.appearance().backgroundColor = .black
UINavigationBar.appearance().backgroundColor = .black
It becomes much darker. It isn't completely opaque though.
Edit: Just watched Modernizing Your UI for iOS 13 This is the way to do it :
The TabView and NavigationView are actually UIHostedController for the legacy UITabBarController and UINavigationController:
let appearance = UITabBarAppearance()
appearance.configureWithOpaqueBackground()
appearance.titleTextAttributes = [.foregroundColor: UIColor.white]
appearance.largeTitleTextAttributes = [.foregroundColor: UIColor .white]
Then set the appearance on the various type of appearance.
tabBar.standardAppearance = appearance
2nd Edit:
extension UINavigationController {
override open func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground()
navigationBar.standardAppearance = appearance
navigationBar.compactAppearance = appearance
navigationBar.scrollEdgeAppearance = appearance
}
}
extension UITabBarController {
override open func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let appearance = UITabBarAppearance()
appearance.configureWithOpaqueBackground()
tabBar.standardAppearance = appearance
}
}
There should be a cleaner way to get to both tabBar and navBar.
Reference: https://developer.apple.com/videos/play/wwdc2019/224/

I was using UIKit with SwiftUI. My Tab bar was creating in storyboard but the view for which I was getting extra bottom space was a swiftui view as you mentioned. I tried all above solution but Nothing worked for me.
I am using Xcode 12.4 for development. My solution is to mark Translucent to true in storyboard and Bottom extra gray bar was gone.

Just customize it in an extension like this:
extension UITabBarController {
override open func viewDidLoad() {
super.viewDidLoad()
let appearance = UITabBarAppearance()
appearance.backgroundColor = .black
tabBar.standardAppearance = appearance
}
}
Pay attention that the overridden function must be viewDidLoad(). At least it doesn't work for me when it is a viewDidAppear(:) function.

It's easier than all that, just delete the next line:
UITabBar.appearance().isTranslucent = false

Related

Xcode 13 - Navigation bar and status bar text color changing in swift OS 15

Recently I updated my Xcode to 13 and after that, I am facing some issues with the navigation bar and Status bar. I am using the tab bar in my view controller. After updating the Xcode, according to the version, I added some code related to the navigation bar.
if #available(iOS 15.0, *) {
tableView.sectionHeaderTopPadding = 0
let appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground()
appearance.backgroundColor = UIColor(red: 58/255,green: 24/255, blue: 93/255, alpha: 1.0)
appearance.titleTextAttributes = [NSAttributedString.Key.foregroundColor:UIColor.white]
// Customizing our navigation bar
navigationController?.navigationBar.tintColor = .white
navigationController?.navigationBar.barTintColor = .white
navigationController?.navigationBar.standardAppearance = appearance
navigationController?.navigationBar.scrollEdgeAppearance = appearance
}
Everything is working when I first opened the app. When I click on the other tab and then this tab. The status bar text color is changing.
I tried different ways to set the status bar text color. But nothing worked for me.
Use this function:
extension YourViewController {
override var preferredStatusBarStyle: UIStatusBarStyle {
.lightContent
}
}
If you just want to set to white colour you status bar in the entire project you can easily do it by adding the following keys into your project.plist file:
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<key>UIStatusBarStyle</key>
<string>UIStatusBarStyleLightContent</string>
<key>UIUserInterfaceStyle</key>
<string>Light</string>
So, what does these keys do... You are just defining that you status bar colour will not be controlled by the any view controller and that the default colour will be "light theme" that is pretty much the white colour that you want in this case...
this would be the best approach if you do not intent to update the status bar colour all over the place.
this was tested and is working as expected on Xcode 13 and iOS [13.x,14.x,15.x]
If you want to update to customise or update the colours for the navigation bar you would should be able to do with an extension like this one bellow, just few examples but you guys should get what I mean:
extension UINavigationBar {
func clearBackground() {
let navBarAppearance = UINavigationBarAppearance()
navBarAppearance.configureWithTransparentBackground()
navBarAppearance.shadowColor = UIColor.clear
navBarAppearance.titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.white]
self.standardAppearance = navBarAppearance
self.scrollEdgeAppearance = navBarAppearance
}
func blackColor() {
// Create an Appearance and customise as you wish.
// in this case just a black background with titles in white.
let navBarAppearance = UINavigationBarAppearance()
navBarAppearance.configureWithOpaqueBackground()
navBarAppearance.shadowColor = UIColor.black
navBarAppearance.titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.white]
self.standardAppearance = navBarAppearance
self.scrollEdgeAppearance = navBarAppearance
}
}
with this code you should be able to easy update on any view controller by just calling something like:
override func viewDidLoad() {
super.viewDidLoad()
// set the navigation bar color as transparent
self.navigationController?.navigationBar.clearBackground()
}

How to make UITabBar blurry, in Swift

I am trying to make UITabBar look blur.
I am trying to make something like this in this image
But my view now looks like this
This is my view for tabbar
I tried this code in UITabbarController -
Code:
class TabBarViewController: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
configureTabbar()
}
func configureTabbar(){
let blurEffect = UIBlurEffect(style: .dark)
let vibrancyEffect = UIVibrancyEffect(blurEffect: blurEffect)
let vibrancyView = UIVisualEffectView()
vibrancyView.frame = tabBar.bounds
vibrancyView.autoresizingMask = .flexibleWidth
vibrancyView.effect = vibrancyEffect
tabBar.insertSubview(vibrancyView, at: 0)
tabBar.isTranslucent = true
tabBar.backgroundImage = UIImage()
tabBar.backgroundColor = .clear
tabBar.barStyle = UIBarStyle.black
tabBar.barTintColor = UIColor.clear
}
System bars such as UINavigationBar, UITabBar & UIToolbar are translucent by default and you don't need to add anything extra to get that effect.
You just need to make sure that your view extends it's content under system bars. You can go to storyboard and make sure the Extend Edges - Under Bottom Bars is checked for your UIViewController that you plan to see this effect on.

iOS 13 navigationBar.barStyle

I'm applying the new appearance API for NavigationBar and I'm struggling with the status bar content (text). On Info.plist I forced to use the light mode because most of the app is white, but in one of my viewControllers, the navigation bar is dark blue (almost black) so the content within this bar needs to be white.
I used to use navigationBar.barStyle = .black on versions up to iOS 12.4, but for iOS 13 and above it doesn't work anymore. Follow the code I've tried and failed.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if let navController = self.navigationController {
let navBarAppearance = navController.navigationBar.standardAppearance.copy()
navBarAppearance.configureWithOpaqueBackground()
navBarAppearance.shadowImage = UIImage()
navBarAppearance.backgroundColor = LayoutBootstrap.colors.primary.solid // Dark blue
navController.navigationBar.standardAppearance = navBarAppearance
navController.navigationBar.barStyle = .black
}
}
Status bar content is black
PS: On didFinishLaunchingWithOptions I already called a default configuration appearance for NavigationBar and Items
Do you guys have any suggestion?
Thanks in advance.
You need to set the status bar style as well
UIApplication.shared.statusBarStyle = .lightContent

Set UIImagePickerController navigation bar to opaque in iOS 13

I am presenting a UIImagePickerController to pick an image. My code is as simple as:
private lazy var imagePicker: UIImagePickerController = {
let picker = UIImagePickerController()
picker.navigationBar.isTranslucent = false
return picker
}()
func presentPicker() {
imagePicker.sourceType = .photoLibrary
imagePicker.modalPresentationStyle = .fullScreen
present(self.imagePicker, animated: true, completion: nil)
}
I am setting picker.navigationBar.isTranslucent = false to have an opaque navigation bar in the picker controller. Unfortunately this doesn't work on iOS 13 and the navigation & status bars are transparent.
Partial solution:
private func setOpaqueNavigationiOS13() {
UINavigationBar.appearance().backgroundColor = .white
}
private func resetNavigationiOS13() {
UINavigationBar.appearance().backgroundColor = .clear
}
I call the above functions to make the navigation bar opaque and to reset it when dismissing the picker. This makes the navigation bar opaque but the status bar is transparent. I can implement a hack to make the status bar opaque as well but I guess there should be a simpler solution.
EDIT:
I've also tried setting the navigation bar's appearance by the new UINavigationBarAppearance:
if #available(iOS 13.0, *) {
let appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground()
appearance.backgroundColor = .white
UINavigationBar.appearance().standardAppearance = appearance
UINavigationBar.appearance().compactAppearance = appearance
UINavigationBar.appearance().scrollEdgeAppearance = appearance
}
Or:
if #available(iOS 13.0, *) {
let appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground()
appearance.backgroundColor = .white
imagePicker.navigationBar.standardAppearance = appearance
imagePicker.navigationBar.compactAppearance = appearance
imagePicker.navigationBar.scrollEdgeAppearance = appearance
}
Anyone that came up with a fix? Thanks
I am posting my solution in case it's helpful for others.
Although matt's answer is totally correct, it applies when all of you nav bar setup is done through UINavigationBarAppearance. This did not help in my case because I've already done this in AppDelegate:
// Make navigation bar transparent throughout whole app
UINavigationBar.appearance().setBackgroundImage(UIImage(), for: .default)
And as my app showcases a lot of nav bar styling and I needed a quick fix just to satisfy iOS 13 changes I just did this:
// Set nav bar to opaque
if #available(iOS 13.0, *) {
UINavigationBar.appearance().setBackgroundImage(nil, for: .default)
}
Just don't forget to bring it back to transparent if needed.
In iOS 13, the correct way to customize the look of a navigation bar is through the UIBarAppearance architecture (the navigation bar's standardAppearance and so forth). You can apply this directly to the navigation bar or use the UINavigationBar appearance proxy.

How to change Navigation Bar back to translucent after making it transparent

I have a view controller in my navigation stack that needs to have a transparent navigation bar, while still showing the back button.
I'm able to achieve that with one line of code inside viewWillAppear:
self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
However, when I try to go back to the previous view, I'm setting the background image back to nil or .none but I'm losing the translucent effect that was previously on there when I do that.
I've tried setting all the following options in viewWillDisappear and none seem to bring the translucency back. It just appears white no matter what I do. The shadow on the bottom is also gone too:
self.navigationController?.navigationBar.isTranslucent = true
self.navigationController?.navigationBar.barStyle = .default
self.navigationController?.navigationBar.backgroundColor = .none
self.navigationController?.navigationBar.setBackgroundImage(.none, for: .default)
Initial Navigation Bar:
Transparent Navigation Bar:
After Transitioning Back:
In viewWillAppear make the navigation bar transparent
override func viewWillAppear(_ animated: Bool) { self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
self.navigationController?.navigationBar.shadowImage = UIImage()
self.navigationController?.navigationBar.isTranslucent = true
}
And backg to translucent in viewWillDisappear
override func viewWillDisappear(_ animated: Bool) {
self.navigationController?.navigationBar.setBackgroundImage(nil, for: .default)
self.navigationController?.navigationBar.shadowImage = nil
self.navigationController?.navigationBar.isTranslucent = false
}
After spending time poking around in the UINavigationBar internals, I did discover a simple method that seems to work, and does not require any configuration of the standard UINavigationBar attributes we've previously fiddled with to achieve transparency. The following is tested working on iOS 12.2.x:
class TallNavigationBar: UINavigationBar {
private lazy var maskingView: UIView = {
let view = UIView(frame: bounds)
view.backgroundColor = .clear
return view
}()
var isTransparent = false {
didSet {
guard isTransparent != oldValue, let bkgView = subviews.first else { return }
bkgView.mask = isTransparent ? maskingView : nil
}
}
}
Obviously, whenever fiddling (even slightly) with undocumented internals: use at your own risk!
This worked for my app which needs to revert to an opaque navigation bar after popping from a transparent navigation bar.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
navigationController?.navigationBar.setBackgroundImage(nil, for: .default)
navigationController?.navigationBar.shadowImage = nil
navigationController?.navigationBar.isTranslucent = true
navigationController?.navigationBar.backgroundColor = nil
}