Visible UISearchBar changes UINavigationBar background color - ios

A tableview controller is embedded into a navigation controller.
I programmatically added a search bar to the tableview controller's navigation bar. I only changed the navigation bar Background color into something different than Default (purple) - all the rest I left default.
class TableViewController: UITableViewController {
let searchController = UISearchController(searchResultsController: nil)
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.hidesSearchBarWhenScrolling = true
navigationItem.searchController = searchController
}
}
Code above is reduced to bare minimum for demonstration purpose.
All done with Xcode 11 (11A420a).
I ran the project in iOS 12.0 and 13.0 simulators and devices.
iOS 13.0
The search bar shows upon start.
Navigation bar background color is correctly presented.
While scrolling, navigation bar background color remains correct.
With iOS 13.0, all works as expected!
iOS 12.0
The search bar doesn't show upon start.
Navigation bar background color is correctly presented.
While scrolling, navigation bar background color goes white as soon search bar is visible.
I tried to change all kind of color setting in storyboard as well as properties programmatically. I didn't succeed in changing the navigation bar background color when search bar is visible.
It seems (?!) that the navigation bar foreground looses transparency when search bar becomes visible.
If I use a Bar Tint color of the navigation bar (!= Default), all works as expected (and as with iOS 13.0), but I loose the gradient effect, which I would like to keep.
What did I miss?
How can I avoid this?
Bug?

I had some luck with the navigationItem.scrollEdgeAppearance property when facing a similar problem. For example:
vc.navigationItem.scrollEdgeAppearance?.backgroundColor = .red
This is only available on iOS 13 though.
Here's what I ended up doing to get correct colors in the navigation bar while allowing the search controller's scroll bar to hide during scroll:
if #available(iOS 13.0, *) {
let blurEffect = UIBlurEffect(style: .systemUltraThinMaterial)
navbar.standardAppearance.backgroundEffect = blurEffect
navbar.standardAppearance.backgroundColor = appMainColor.withAlphaComponent(0.75)
navbar.standardAppearance.titleTextAttributes = [NSAttributedString.Key.foregroundColor : UIColor.white]
navbar.compactAppearance = nil
navbar.scrollEdgeAppearance = navbar.standardAppearance.copy()
navitem.standardAppearance = nil
navitem.compactAppearance = nil
navitem.scrollEdgeAppearance = nil
}

I don't know if it is the look you're going for but I found if you disable hideSearchBarWhenScrolling the background stops changing color. However, the search bar is always there.
Add this to viewDidLoad():
navigationItem.hidesSearchBarWhenScrolling = false

Related

How to use scrollEdgeAppearance in iOS 15?

Here's Apple's document of scrollEdgeAppearance for UINavigationBar:
When a navigation controller contains a navigation bar and a scroll
view, part of the scroll view’s content appears underneath the
navigation bar. If the edge of the scrolled content reaches that bar,
UIKit applies the appearance settings in this property.
If the value of this property is nil, UIKit uses the settings found in the
standardAppearance property, modified to use a transparent background.
If no navigation controller manages your navigation bar, UIKit ignores
this property and uses the standard appearance of the navigation bar.
When running on apps that use iOS 14 or earlier, this property applies
to navigation bars with large titles. In iOS 15, this property applies
to all navigation bars.
Here's my demo. I embed ViewController into a UINavigationController, then drag a UITableView and set it as the subview of ViewController's view. I set the following appearance properties to UINavigationBar:
class ViewController: UIViewController {
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let redAppearance = UINavigationBarAppearance()
redAppearance.backgroundColor = .red
navigationController?.navigationBar.standardAppearance = redAppearance
let greenAppearance = UINavigationBarAppearance()
greenAppearance.backgroundColor = .green
navigationController?.navigationBar.scrollEdgeAppearance = greenAppearance
}
}
I thought the initial navigation bar should be red, and it should turn green when I scroll the table view. But the truth is it's the other way around.
I did some search and most people just set standardAppearance and scrollEdgeAppearance to the same instance, or set one of them to be nil, so I'm quite confused about these two properties in iOS 15.
You have understood perfectly but backward.
navigationController?.navigationBar.scrollEdgeAppearance = greenAppearance
means the nav bar will be green only when the scrollable view is scrolled all the way down. That is what you see in your first screen shot.
As soon as you scroll up a little bit, the nav bar starts adopting its standard appearance, which is red. That is what you see in your second screen shot.
scrollEdgeAppearance is applied when the edge of the scrollable content reaches the nav bar so what you're seeing is correct. Many people set both scrollEdgeAppearance and standardAppearance to the same since they want the behavior to be no different when the user scrolls but your implementation is certainly a valid use case.

How to make the entire project's navigation bar black in Swift and iOS 9

I want to set the status bar as black for the entire project. I have Pagination, Modal views, Navigation stacks in my project. Is there a way to set the status bar a black for complete project. I've seen this in Android apps. I have tried to set status bar as Light in AppDelegate, have set View-Controllers based navigation bar to NO/YES in plist. Nothing seems to work.
Calling this form application:didFinishLaunchingWithOptions should work.
func setStatusBarBackgroundColor(color: UIColor) {
guard let statusBar = UIApplication.sharedApplication().valueForKey("statusBarWindow")?.valueForKey("statusBar") as? UIView else {
return
}
statusBar.backgroundColor = color
}

Navigation Bar color

I'm building an map app and have label with information of my route. I've set programmatically color of the label and navigation bar with the same hex. But while testing the app, I've noticed that they are different a bit. Can anybody tell me, what is wrong?
screenshot
Main color is in Util class; nav bar appearance is set in app didFinishLaunchingWithOptions method; label color is set in viewWillAppear of my map VC
public static let mainColor = UIColor(fromHexCode: "#335E40")
UINavigationBar.appearance().barTintColor = Util.mainColor
infoLabel.backgroundColor = Util.mainColor
Did you turn off the transition?
UINavigationBar.appearance().translucent = false

Search bar bug - iOS

In my app I have this kind of bug:
When I scroll down, the content of table is seen above the search bar. What can be the reason?
override func viewDidLoad() {
super.viewDidLoad()
self.resultSearchController = ({
let controller = UISearchController(searchResultsController: nil)
controller.searchResultsUpdater = self
controller.dimsBackgroundDuringPresentation = false
controller.searchBar.sizeToFit()
controller.searchBar.barTintColor = UIColor(red: 52.0/255.0, green: 73.0/255.0, blue: 94.0/255.0, alpha: 1.0)
self.tableView.tableHeaderView = controller.searchBar
return controller
})()
self.tableView.reloadData()
}
The iOS Human Interface Guidelines list 3 methods to prevent content from showing through the status bar.
Use a navigation controller to display content. A navigation controller automatically displays a status bar background and it
ensures that its content views don’t appear behind the status bar. (To
learn more about navigation controllers, see Navigation Controllers.)
Create a nondistracting custom image—such as a gradient—and display it behind the status bar. To ensure that the image stays
behind the status bar, you could use a view controller to keep the
image above a scrolling view or you could use a scrolling view to keep
it pinned to the top.
Position content to avoid the status bar area (that is, the area defined by the app’s statusBarFrame property). If you do this, you
should use the window’s background color to provide a solid color
behind the status bar.
You should make the status bar not translucent.
The status bar's color is a property of UIApplication. You need to set it to a valid UIStatusBarStyle.
The new UISearchController has been designed to work with a UITableView and a UINavigationBar. Its functionality depends on your navigation bar being present. when the search bar has content in its text field, it will be latched on top of the page under the navigation bar. well, you don't have any navigation bar, it will latch to the top view guide and it always takes into account the status bar (if present) I guess the only way you can resolve your problem without an actual navigation bar is to add a view under status bar and make it opaque just like your search bar. it's a bit hacky but it's alright in my book.

UISearchController doesn't work properly with a non-translucent UINavigationBar

Currently I am trying to embed a UISearchController into my application. But the UISearchBar, which is a property of the UISearchController, doesn't get displayed properly, if the UINavigationBar is non-translucent. Usually after tapping the UISearchBar property, the UINavigationBar moves up to make room for the UISearchBar. You can see the result on the following screenshot:
https://www.dropbox.com/s/172k63zr2bhj84t/Normal_behaviour.png?dl=0
But if the "translucent" property of the UINavigationBar is set to "NO", the UISearchBar doesn't get displayed properly, because the background of the status bar remains transparent, as you can see on the following screenshot:
https://www.dropbox.com/s/v5cnxoj9ms6976r/Wrong_behaviour.png?dl=0
To demonstrate this weird behaviour, I have modified the sample project provided by Apple:
https://developer.apple.com/library/ios/samplecode/TableSearch_UISearchController/Introduction/Intro.html
Here you can download the modified version:
https://www.dropbox.com/s/7icfe6kap98g1e8/TableSearchwithUISearchControllerObj-CandSwift_MODIFIED.zip?dl=0
The modification is in file "APLMainTableViewController.m" line 33.
It's clearly a bug (rdar://20942583).
My workaround is to set
self.edgesForExtendedLayout = UIRectEdgeAll;
self.extendedLayoutIncludesOpaqueBars = YES;
This allows you to keep the navigation bar opaque. The downside is that the content flows below the bar even if it can't be seen, creating some overhead.
All I needed was:
func viewDidLoad() {
extendedLayoutIncludesOpaqueBars = true
}
One workaround for this is to make the status bar translucent just before the search is going to become active, and remove the translucency when the search is about become inactive.
You can do this by registering your view controller as a delegate of UISearchController, and implementing the willPresentSearchController and willDismissSearchController methods. For example (in Swift):
Declare your view controller as a delegate of UISearchController:
class MyViewController: UITableViewController, UISearchControllerDelegate
Don't forget to actually set it as the delegate, for instance in viewDidLoad add:
searchController.delegate = self
And finally:
func willPresentSearchController(searchController: UISearchController) {
navigationController?.navigationBar.translucent = true
}
func willDismissSearchController(searchController: UISearchController) {
navigationController?.navigationBar.translucent = false
}
Ok, this one is a SUPER pain to debug but not that bad to fix. It's all down to the way Apple changed the appearance of navigation bars. It can be fixed by creating a UINavigationBarAppearance object, configuring it with the visual properties you want (i.e. background colour etc) and then assigning it to standardAppearance and scrollEdgeAppearance on UINavigationBar.appearance() - you can have two different instances with different settings if you want.
A simple implementation might look like this:
let appearance = UINavigationBarAppearance()
appearance.configureWithDefaultBackground()
appearance.backgroundColor = barColor
appearance.titleTextAttributes = [NSAttributedString.Key.foregroundColor: textColor]
UINavigationBar.appearance().standardAppearance = appearance
UINavigationBar.appearance().scrollEdgeAppearance = appearance
(Naturally replace barColor and textColor with the colours of your choice!)
if someone have a problem like non-translucent hidden the search bar u can just had this :
self.definesPresentationContext = true
Regards

Resources