Navigation bar gets blocked after pressing Cancel in UISearchController - swift

I`m preparing app for iOS 13, and get bug with search controller in navigation bar. How to solve navigation bar glitch?
let search = UISearchController(searchResultsController: nil)
search.dimsBackgroundDuringPresentation = false
search.searchResultsUpdater = self
search.hidesNavigationBarDuringPresentation = false
self.definesPresentationContext = true
search.searchBar.isTranslucent = false
self.navigationItem.searchController = search
self.navigationItem.hidesSearchBarWhenScrolling = true
Press Cancel and navigation bar items becomes untouchable.
Pushing view controller leads to navigation bar item overlap.
I have created test project on git https://github.com/eKroman/TESTsearchBar
Bug appears on iOS 13 beta (tested on iPad) using from Xcode 11 from beta 7 (maybe older beta) to Xcode 11 GM seed 2.
Does not appear on simulators.

I encountered the same problem, if I cancel the searchBar and change the navigationItem.title then I have a double title 👍. It's like a ghost layer of the navigation bar stays here in the navigation controller.
This is how I fixed it:
searchController.hidesNavigationBarDuringPresentation = true
Probably best to use it until Apple fix this issue.
I also noticed that the back button switch to default color (blue), as if the navigationBar TintColor was reset.
Config:
- Xcode 11.0 (11A420a)
- iOS 13.1 (17A5844a)

For the back button reset to default color (blue) in #CoachThys's answer, I manage to work around it by the code below.
if #available(iOS 13.0, *) {
let appearance = UINavigationBarAppearance()
/* .. set other things on appearances */
appearance.buttonAppearance.normal.titleTextAttributes = [.foregroundColor: color]
standardAppearance = appearance
compactAppearance = appearance
scrollEdgeAppearance = appearance
}
However, I cannot find a way to work around the back indicator image which is still reset to blue color briefly.

Add custom backbutton with a image would fixed the new bug. It works well for me.
let negativeSpacer = UIBarButtonItem(barButtonSystemItem: .fixedSpace, target: nil, action: nil)
negativeSpacer.width = -8
self.navigationItem.leftBarButtonItems = [negativeSpacer, leftBarButtonItem]

Related

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.

Is this new navigation bar behaviour in xcode 11 beta a bug or intended?

I noticed after compiling one of my apps in Xcode 11 beta, that navigation bars have no background when prefersLargeTitles is set. Is this intended behavior?
I noticed this is how the messages app works now when scrolling down and a large title is visible there is no nav bar background.
Here is the code used to set up the navBar attributes:
override func viewWillAppear(_ animated: Bool) {
let textAttributes = [NSAttributedString.Key.foregroundColor:ThemeManager.shared.default1]
self.navigationController?.navigationBar.largeTitleTextAttributes = textAttributes
self.navigationController?.navigationBar.titleTextAttributes = textAttributes
self.navigationController?.navigationBar.tintColor = ThemeManager.shared.default1
self.navigationController?.setNavigationBarHidden(false, animated: true)
self.navigationController?.navigationBar.prefersLargeTitles = true
let nav = self.navigationItem
nav.title = "My Profile"
}
Here are a couple of images showing the difference:
left, compiled on Xcode 10, right, Xcode 11 beta:
Once you scroll up on the 11 Beta version, the background fades back in. Note that apps that are not compiled in Xcode 11 beta will still behave in the normal way, only changes after compiling for some reason. Is this intended, and how would I bring back the original behavior?
This is intended behavior for iOS 13.
Apple's idea (terrible in my opinion) is that the title should merge with the content to show that it is related. Once you start scrolling, when content goes behind the title bar then the title bar will take the "correct" appearance.
The reason this is terrible is because everyone has currently planned all of their UI without this behavior. So the new behavior should be opt-in instead of forcing everyone to opt-out (i.e. the change breaks everyone's code and if you're going to break everyone's code at least you should be clear about how to keep the tried and true behavior of the last 10 years).
As in your case, the result looks horrible. The result looks horrible in my case too.
Apple doesn't give answers but says that you should be using
- scrollEdgeAppearance
From UINavigationBar in order to control the appearance of the bar when content is aligned top-of-content to bottom-of-navbar ... in my case this method returns nil though so I'm currently unsure how we're supposed to use this.
This seems to be discussed here as well:
New UINavigationBar appearance in detail pane of UISplitViewController in iOS 13
So the current workaround would seem to be this in your view controller:
- (void)viewDidLoad;
{
[super viewDidLoad];
if (#available(iOS 13,*)){
UINavigationBar *bar =self.navigationController.navigationBar;
bar.scrollEdgeAppearance = bar.standardAppearance;
}
}
It works, but if it's the intended approach, I don't know...
EDIT:
Doing this does seem to block any additional direct customization to the UINavigationBar as has been noted. Possible that adjusting the scrollEdgeAppearance from here is the way to go. Ugly. Ugly. Ugly.
EDIT: Progress... this is working now for managing the background. You need to call this instead of setting barTint directly.
#interface UINavigationBar (Compatibility)
- (void)setCompatibleTint:(UIColor *)fg andBarTint:(UIColor *)bg;
#end
#implementation UINavigationBar (Compatibility)
- (void)setCompatibleTint:(UIColor *)fg andBarTint:(UIColor *)bg;
{
self.tintColor = fg;
self.barTintColor = bg;
if (#available(iOS 13,*)){
// we need to tell it to adopt old style behavior first
UINavigationBarAppearance *appearance = self.standardAppearance;
appearance.backgroundColor = bg;
NSDictionary *attributes = self.titleTextAttributes;
appearance.titleTextAttributes = attributes;
attributes = self.largeTitleTextAttributes;
appearance.largeTitleTextAttributes = attributes;
self.scrollEdgeAppearance = appearance;
self.standardAppearance = appearance;
self.compactAppearance = appearance;
}
}
#end
I'm not entirely sure yet on the text attributes but it seems to flow from the background color. It's a complete PITA.
It would be nicer to set this as a subclass and override barTint but of course a lot of the UIKit objects create these bars themselves so you won't get the subclass.
Swift version of dbquarrel's solution.
First declare your textAttributes:
let textAttributes = [NSAttributedString.Key.foregroundColor:UIColor.red]
Use these in a UINavigationBarAppearance() to enable you to change the colour of the text in 3 different modes (scollEdge, standard and compact).
override func viewDidLoad() {
super.viewDidLoad()
if #available(iOS 13.0, *) {
let appearance = UINavigationBarAppearance()
appearance.largeTitleTextAttributes = textAttributes
appearance.titleTextAttributes = textAttributes
let bar = self.navigationController?.navigationBar
bar?.scrollEdgeAppearance = appearance
bar?.standardAppearance = appearance
bar?.compactAppearance = appearance
} else {
// Fallback on earlier versions
}
}

iOS 11 Extra Space on NavigationBar

I changed my searchBar code from:
self.navigationItem.titleView = searchNavigation.searchController.searchBar;
to:
if (#available(iOS 11.0, *)) {
self.navigationItem.searchController = searchNavigation.searchController;
self.navigationController.navigationBar.prefersLargeTitles = NO;
self.navigationItem.largeTitleDisplayMode = UINavigationItemLargeTitleDisplayModeNever;
} else {
self.navigationItem.titleView = searchNavigation.searchController.searchBar;
}
but when try on ios 11 it looks like
there is extra space over searchBar and when i start to typing its slide top top and looks normal
First for iOS 11 you are assigning your search controller to the navigation items searchController properties instead of as it's titleView. If you do that then the search bar appears below the navigation bar as you have seen.
Second there is a property on the UISearchController called hidesNavigationBarDuringPresentation which controls whether the search bar moves up to hide the navigation bar when in use.
To replicate for iOS 11 what you have for previous versions do this instead:
if (#available(iOS 11.0, *)) {
self.navigationItem.titleView =
searchNavigation.searchController.searchBar;
searchNavigation.searchController.hidesNavigationBarDuringPresentation = NO;
self.navigationController.navigationBar.prefersLargeTitles = NO;
self.navigationItem.largeTitleDisplayMode = UINavigationItemLargeTitleDisplayModeNever;
} else {
self.navigationItem.titleView =
searchNavigation.searchController.searchBar;
}
As previous answers have mentioned, setting the navigation bar's searchController as the desired search bar will produce the search bar sitting below the navigation bar's new "large title".
To stop this new behaviour you need to override the navigation bar's titleView with the search bar itself and disable the search controller's animation that hides the large title once input has started. This can be done like so:
navigationItem.titleView = searchController.searchBar
searchController.hidesNavigationBarDuringPresentation = false

Change Background Color Status Bar iOS

So, I'm trying to make this:
i tried using UIView in back of Status bar and set the color to orange, but when running, The UIView displayed right under the status bar, so it's still White
i'm trying many solution in the internet but none of them work. Yes it works but when i move to other view controller and back again, The color dissapeared. What should I do? i'm using swift
UIApplication.shared.statusBarStyle = .lightContent
UINavigationBar.appearance().clipsToBounds = true
let statusBar: UIView = UIApplication.shared.value(forKey: "statusBar") as! UIView
statusBar.backgroundColor = UIColor.orange
Try using this code in your appDelegate's method application didFinishLaunchingWithOptions