Status Bar becomes white in iOS when using UISearchController in iOS 13 - ios

have a weird situation here. When I use the UISearchController, I get this appearance first (as expected)
But when you select inside the TextField to start searching, the Status Bar becomes completely white (or black if you are in dark mode)
This never used to happen. Is there some setting in UISearchController that tells it to use a certain Status Bar style when using the Search Bar?
I'd prefer it stay the color it was before selecting the TextField
---EDIT---
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: "", style: UIBarButtonItem.Style.plain, target: nil, action: nil)
frc = getFRC()
frc.delegate = self
self.resultsSearchController.delegate = self
let searchBar = self.resultsSearchController.searchBar
self.resultsSearchController.searchResultsUpdater = self
self.resultsSearchController.obscuresBackgroundDuringPresentation = false
self.resultsSearchController.extendedLayoutIncludesOpaqueBars = true
searchBar.sizeToFit()
self.tableView.tableHeaderView = searchBar
searchBar.placeholder = "Catalog Search"
searchBar.barTintColor = UIColor.darkAqua
searchBar.searchTextField.backgroundColor = UIColor.white
self.definesPresentationContext = true
searchBarHeight = searchBar.frame.height
do {
try frc.performFetch()
} catch {
error.tryError(tryMessage: "Perform initial fetch", loc: self)
}
if tutorials.catalog {
createTutorialTab(segueNameOnOpen: "catalogTutorial")
}
}

You use this function to change status bar colors, it's a kind of hack to deal with status bar ;). If you are using one theme status bar in whole app , call this function from didFinishLaunching in AppDelegate.
func changeStatusBar(backgroundColor: UIColor, contentColor:UIColor) {
if let statusBar = UIApplication.shared.value(forKey: "statusBar") as? UIView {
statusBar.backgroundColor = backgroundColor
statusBar.setValue(contentColor, forKey: "foregroundColor")
}
}

Related

How to remove shadow below UINavigationBar with UISearchController

I could successfully remove the shadow below the navigation bar with the following line of code.
self.navigationController?.navigationBar.shadowImage = UIImage()
When I added a search controller however, the shadow reappeared.
self.navigationItem.searchController = UISearchController(searchResultsController: nil)
I tried the following, but resulted an unexpected behavior.
self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
self.navigationController?.navigationBar.barTintColor = .white
self.navigationController?.navigationBar.isTranslucent = false
How do I remove the shadow under a navigation bar when there is a search controller attached?
I have not found good solution too...
for now I will hide it this way:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if let imageView = navigationItem.searchController?.searchBar.superview?.subviews.first?.subviews.first as? UIImageView {
imageView.isHidden = true
}
}
Here's the solution that I use
Create a separate class extending a UINavigationController instance, lets call it BaseNavigationController. Here's your class for you
If you are using storyboards, assign BaseNavigationController to your UINavigationController scene in the storyboard
If you are initializing a navigation controller via code, ex: UINavigationController.init(rootViewController: someViewControllerInstance) then simply use BaseNavigationController.init(rootViewController: someViewControllerInstance)
An example of the class is shown below:
open class BaseNavigationController:UINavigationController {
override open func viewDidLoad() {
super.viewDidLoad()
setNavigationBar()
setNavBarBorder(false)
}
func setNavigationBar(color:UIColor?=UIColor.white, tint:UIColor?=UIColor.darkGray){
let appearance = UIBarButtonItem.appearance()
appearance.setBackButtonTitlePositionAdjustment(UIOffset.init(horizontal: 0.0, vertical: 0), for: .default)
self.navigationBar.barTintColor = color!
self.navigationBar.isTranslucent = false
self.navigationBar.tintColor = tint!
self.navigationBar.titleTextAttributes = [ NSAttributedString.Key.foregroundColor: tint! ]
}
func setTitleColor(_ color:UIColor?=UIColor.darkGray){
}
func setNavBarBorder(_ enable:Bool) {
self.navigationBar.setBackgroundImage((enable ? nil : UIImage()), for: UIBarMetrics.default)
self.navigationBar.shadowImage = (enable ? nil : UIImage())
self.navigationBar.setValue(true, forKey: "hidesShadow")
}
}
Now, the fun part, if you are handling ambiguous layout you might need to do this in viewWillLayoutSubviews otherwise putting this bit of code in viewWillAppear
of the viewController instance.
(self.navigationController as? BaseNavigationController)?. setNavBarBorder(false)
the interesting bit of code is in self.navigationBar.setValue(true, forKey: "hidesShadow"), for some versions of iOS.
You can instead add searchBar to your viewController in storyBoard and set its Search Style property to Minimal and it'll be look like this:
My little contribution about this issue. Of course, it is not the right way to do it but it's working for opaque navigation bar. The idea is to add a view on top of this shadow.
let searchBar = searchController.searchBar
let maskView = UIView(frame: .zero)
maskView.backgroundColor = .white // or any color you want
searchBar.addSubview(maskView)
//We need to use constraint so the mask view follow the search bar animation
maskView.translatesAutoresizingMaskIntoConstraints = false
let views = ["maskView": maskView]
searchBar.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-(0)-[maskView]-(0)-|",
options: NSLayoutConstraint.FormatOptions.alignAllCenterY,
metrics: nil,
views: views))
searchBar.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:[maskView(1)]-(-1)-|",
options: NSLayoutConstraint.FormatOptions.alignAllCenterX,
metrics: nil,
views: views))

UISearchController does not display as expected

I'm trying to add a UISearchController to a UIViewController that contains a UITableView (and an MKMapView too, but hopefully that's not the problem). I followed Ray Wenderlich's tutorial but I can't get the same result in terms of behaviour.
Here is my viewDidLoad:
override func viewDidLoad() {
super.viewDidLoad()
// Setup the Search Controller
searchController.searchResultsUpdater = self
searchController.obscuresBackgroundDuringPresentation = false
searchController.searchBar.placeholder = NSLocalizedString("Search references by project, customer or city", comment: "")
if #available(iOS 11.0, *) {
navigationItem.searchController = searchController
navigationItem.hidesSearchBarWhenScrolling = true
} else {
tableView.tableHeaderView = searchController.searchBar
}
definesPresentationContext = true
self.modeSelector.layer.cornerRadius = 5.0
if let split = splitViewController {
let controllers = split.viewControllers
detailViewController = (controllers[controllers.count - 1] as! UINavigationController).topViewController as? ReferenceViewController
}
self.navigationItem.rightBarButtonItem?.isEnabled = false
}
Note that the #available test in the middle is because I need to support iOS up to 9.1.
Now I see several problems:
The search bar appears right away and I can't hide it by scrolling
When I focus the search bar, the top of the tableview doesn't stick to the bottom of the navigation item:
The only major difference I see with Ray Wenderlich's sample project is that since I created my project with Xcode 9, my storyboard doesn't use top and bottom layout guides, but safe areas. Don't know if it's relevant, but that's the only thing I see.
Any idea what's going on and how I could fix this?
If you need to support iOS up to 9.1, you probably use emulator with version older than 9.1. Therefore, "maybe" obscuresBackgroundDuringPresentation doesn't affect the searchController properly, since it's only available on iOS 9.1 or newer. Add dimsBackgroundDuringPresentation to support up to 9.1:
if #available(iOS 9.1, *) {
searchController?.obscuresBackgroundDuringPresentation = false
} else {
searchController?.dimsBackgroundDuringPresentation = false
}
If this doesn't help to display as expected, I'm almost sure that the problem is about your layout constraints. Please add your current constraints if you couldn't bring your layout in compliance with safe area.
use this below line of code into your viewDidload
self.navigationController?.navigationBar.isTranslucent = false
Hope this will help you
If you are using xcode 9 (ios 11). Then the thing you really want to do is -
Use the new Broader navigation bars which are the new highlights in the ios 11 devices. But as there are many who have not shifted to ios-11, previous version devices are also taken into consideration.
For adding the search bar to the newer navigation bars I have used the following function which gives a search bar on scrolling and hides it when user scrolls the page.
func addSearchBar() {
if #available(iOS 11.0, *) {
let sc = UISearchController(searchResultsController: nil)
sc.delegate = self
let scb = sc.searchBar
scb.tintColor = UIColor.white
scb.barTintColor = UIColor.white
//Change the colors as you like them
if let textfield = scb.value(forKey: "searchField") as? UITextField {
textfield.textColor = UIColor.blue
if let backgroundview = textfield.subviews.first {
// Background color
backgroundview.backgroundColor = UIColor.white
// Rounded corner
backgroundview.layer.cornerRadius = 10;
backgroundview.clipsToBounds = true;
}
}
if let navigationbar = self.navigationController?.navigationBar {
navigationbar.barTintColor = UIColor.white
}
navigationItem.searchController = sc
navigationItem.hidesSearchBarWhenScrolling = true
}else{
//add the logic for previous version devices here.
}
I have also set the
self.navigationController?.navigationBar.prefersLargeTitles = true; in viewDidLoad as there is a bug in xcode9 and setting it from the interface builder does not work(yet).
The following method has been taken from here

Customize the searchController of navigationItem , but doesn't work with iOS 11

I have searched the similar question UISearchController iOS 11 customizationbut al the methods in the comments couldn't help me out.So I want to ask it again.
I used the following codes to set the appearance of the searchBar.
Extension the UISearchBr to get the textField and placeHolderLabel:
extension UISearchBar{
var textField: UITextField?{
if let textField = self.value(forKey: "searchField") as? UITextField {
return textField
}
return nil
}
var placehloderLabel:UILabel?{
if let placeholderLabel = textField?.value(forKey: "placeholderLabel") as? UILabel{
return placeholderLabel
}
return nil
}
}
Customize a subclass of UISearchController:
class CustomSearchController:UISearchController{
override init(searchResultsController: UIViewController?) {
super.init(searchResultsController: searchResultsController)
self.definesPresentationContext = true
self.dimsBackgroundDuringPresentation = false
self.hidesNavigationBarDuringPresentation = true
self.searchBar.searchBarStyle = .minimal
self.searchBar.placeholder = "搜索歌单内歌曲"
self.searchBar.textField?.textColor = UIColor.white
self.searchBar.placehloderLabel?.textColor = .white
self.searchBar.placehloderLabel?.font = UIFont.systemFont(ofSize: 15)
}
Set prefersLargeTitles UINavigationBar.appearance().prefersLargeTitles = true
If navigationItem.searchController = searchController and the result is as follows (the appearance of the searchBar DOESN'T make change):
But if I set navigationItem.titleView = searchController.searchBar,it makes:
Does the iOS 11 permit developers to change the searchBar's
appearance?If yes,I wonder how to customize it ?Any
point is appreciated.Thanks!
Working with color and UINavigationItem's search controller
This code is in the AppDelegate class.
UISearchBar.appearance().tintColor = UIColor(named: "Button") // using this to set the text color of the 'Cancel' button since the search bar ignores the global tint color property for some reason
if #available(iOS 11.0, *) {
// Search bar placeholder text color
UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).attributedPlaceholder = NSAttributedString(string: "Search", attributes: [NSForegroundColorAttributeName: UIColor.white])
// Search bar text color
UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).defaultTextAttributes = [NSForegroundColorAttributeName: UIColor.red]
// Insertion cursor color
UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).tintColor = UIColor.red
} else {
// Fallback on earlier versions
}
// Search bar clear icon
UISearchBar.appearance().setImage(UIImage(named: "clear"), for: .clear, state: .normal)

UINavigationBar : Add SearchBar as TitleView

I want to add uisearchbar in place of title of controller.
I am facing 2 problems currently.
1)
I do not know from where this gray background is coming. Please check this picture.
2) I need this searchbar in other inner screens also. But when I push another controller this searchbar is removed.
Here is my code :
// Seachbar Container View
let searchBarContainer = ERView(frame: CGRectMake(0,0,280,44))
searchBarContainer.autoresizingMask = [.FlexibleWidth]
searchBarContainer.backgroundColor = UIColor.clearColor()
// Search Bar
let searchBar = ERSearchBar(frame: searchBarContainer.bounds)
searchBarContainer.addSubview(searchBar)
// Add View as Title View in Navigation Bar
self.navigationController!.navigationBar.topItem?.titleView = searchBarContainer
Here is Code of my UISearchBar Class
func commonInit() -> Void {
// Update UI
if let searchField = self.valueForKey("searchField") as? UITextField{
// To change background color
searchField.backgroundColor = UIColor.appNavigationBarDarkRedColor()
// Tint Color
if let leftViewRef = searchField.leftView {
leftViewRef.tintColor = UIColor.whiteColor()
}else if let imgLeftView = searchField.leftView as? UIImageView{
imgLeftView.tintColor = UIColor.whiteColor()
}
// Font Color
searchField.font = UIFont.robotoRegularFont(WithSize: 14.0)
// Text Color
searchField.textColor = UIColor.whiteColor()
// PlaceHolder Attributes
searchField.attributedPlaceholder = NSAttributedString(string: "Search", attributes: [NSForegroundColorAttributeName:UIColor.whiteColor()])
}
self.setImage(UIImage(named: "ic_search_white"), forSearchBarIcon: UISearchBarIcon.Search, state: UIControlState.Normal)
// To change placeholder text color
}
Please someone help me here.
For 1) Set the searchBarStyle property to minimal. This will provides no default background color in UIsearchBar.
2)I'm not quite sure what'd you mean by "inner screen". But if what you want is a Search Bar that can work across different view controllers, UISearchController is the one you're looking for.
You can fine the Apple sample code here

UINavigationBar tint color does not update

I am implementing a dark mode in my app. Here is my code (that I call when the screen is double tapped):
if darkMode == false {
UINavigationBar.appearance().tintColor = UIColor(hexString: "#3A3A3A")
UINavigationBar.appearance().titleTextAttributes = [NSForegroundColorAttributeName:UIColor.whiteColor()]
UIApplication.sharedApplication().statusBarStyle = UIStatusBarStyle.LightContent
} else {
UIApplication.sharedApplication().statusBarStyle = UIStatusBarStyle.Default
UINavigationBar.appearance().barTintColor = UIColor(hexString: "#FFFDF3")
UINavigationBar.appearance().titleTextAttributes = [NSForegroundColorAttributeName:UIColor.blackColor()]
The only thing that updates is my status bar, but the navigation bar does update after I go into another view and return back to the main view. Why is that? Is there something I'm doing wrong?
I was just dealing with the same issue, turns out if you change appearance() proxy at runtime it doesn't have any effect. You need to change directly the properties of instances. So what you need to do is have subclassed UINavigationBarController with method where you set the colors and status bar appearance, for instance:
class ColorNavigationController: UINavigationController {
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
setupForColor(UIFactory.sharedInstance.tintColor) //provides default color
}
func setupForColor(color: UIColor) {
navigationBar.tintColor = color
navigationBar.titleTextAttributes = [NSForegroundColorAttributeName:UIColor.whiteColor()]
UIApplication.sharedApplication().statusBarStyle = UIStatusBarStyle.LightContent
}
}
Then when you double tap the screen:
if let colorNavigationController = self.navigationController as? ColorNavigationController {
colorNavigationController.setupForColor(UIColor.redColor) // based on your current scheme
}
Got it. You can't change appearance() at runtime, but you can just do navigationController?.navigationBar.tintColor = UIColor.redColor()

Resources