Is it possible to customize UINavigationBar by protocol? - swift

I want to customize UINavigationBar for some view controllers. For some reasons, I cannot just simply extend UIViewController. So I was trying to do it by a protocol.
What I have tried:
protocol TransparentNavigationBarProtocol {
func makeNavigationBarTransparent()
}
extension TransparentNavigationBarProtocol where Self: UIViewController {
func makeNavigationBarTransparent() {
if let navController = navigationController {
navController.navigationBar.setBackgroundImage(UIImage(), for: .default)
navController.navigationBar.shadowImage = UIImage()
navController.navigationBar.tintColor = UIColor.white
navController.navigationBar.barStyle = .blackTranslucent
navController.navigationBar.titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.white]
navController.navigationBar.backgroundColor = .clear
}
}
}
I added some breakpoints which show the function had been called successfully but the navigationBar didn't change. So I was wondering is it possible to achieve this by protocols?

For Xcode11, you need set a image, not nil
Also, in your viewcontroller's viewWillAppear, you need call makeNavigationBarTransparent()
func makeNavigationBarTransparent() {
if let navController = navigationController {
navController.navigationBar.setBackgroundImage(UIImage(), for: .default)
navController.navigationBar.shadowImage = UIImage()
navController.navigationBar.tintColor = UIColor.init(red: 74/255, green: 74/255, blue: 74/255, alpha: 1)
navController.navigationBar.barStyle = .default
navController.navigationBar.titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor(red: 74/255, green: 74/255, blue: 74/255, alpha: 1)]
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
makeNavigationBarTransparent()
}

Related

How to customise UISearchController?

I'm using a UISearchController in my application but I can't figure a way to customise it. I looked here in Stackoverflow but none of the confirmed answers worked for me. I tried looking in more places but nothing works.
This is my code:
import UIKit
class MainVC: UIViewController {
lazy var mSearchBarController: UISearchController = {
let mSearchBar = UISearchController(searchResultsController: nil)
mSearchBar.searchBar.barStyle = .default
mSearchBar.searchBar.placeholder = "enter city here"
mSearchBar.searchBar.tintColor = UIColor.white
return mSearchBar
}()
override func viewDidLayoutSubviews() {
setupSearchBar()
}
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor(red: 80/255, green: 135/255, blue: 179/255, alpha: 1.0)
setupNavBar()
self.navigationItem.searchController = mSearchBarController
}
private func setupNavBar(){
navigationItem.title = "Home"
navigationController?.navigationBar.prefersLargeTitles = true
navigationItem.hidesSearchBarWhenScrolling = true
}
private func setupSearchBar(){
let mSearchTextField = mSearchBarController.searchBar.value(forKey: "searchField") as? UITextField
mSearchTextField?.textColor = UIColor(red: 255/255, green: 245/255, blue: 139/255, alpha: 1.0)
let mAttributedPlaceholder = NSMutableAttributedString(string: "enter city here", attributes: [NSAttributedString.Key.foregroundColor : UIColor(red: 255/255, green: 245/255, blue: 139/255, alpha: 1.0)])
mSearchTextField?.attributedPlaceholder = mAttributedPlaceholder
for view in mSearchBarController.searchBar.subviews {
for subview in view.subviews {
if let textField = subview as? UITextField {
textField.backgroundColor = UIColor.red
textField.textColor = UIColor.white
}
}
}
}
}
I can't figure a way to change the textColor of the searchBar nor the backgroundColor of it.
This is what I get:
See I use this simple code to change the textColor and backgroundColor of seacrhBar:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var searchBar: UISearchBar!
override func viewDidLoad() {
super.viewDidLoad()
for view in searchBar.subviews {
for subview in view.subviews {
if let textField = subview as? UITextField {
textField.backgroundColor = UIColor.red
textField.textColor = UIColor.white
}
}
}
}
for reference you can check:-
How can I change the UISearchBar search text color? (for textcolor)
http://jitu1990.blogspot.com/2017/06/textcolor-and-backgroundcolor.html (for backgorund color)

How to set navigation controller settings only one time

In my swift app I've many navigation controller and for each of them I want to set this settings:
navigationController?.navigationBar.backIndicatorImage = #imageLiteral(resourceName: "backArrow").withRenderingMode(.automatic)
navigationController?.navigationBar.backIndicatorTransitionMaskImage = UIImage(named: "backArrow")
navigationItem.backBarButtonItem = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)
navigationItem.backBarButtonItem?.tintColor = UIColor(red: 235/255, green: 235/255, blue: 235/255, alpha: 1)
How can I set this settings only one time, I mean without write this code for each class?
Create a BaseViewController like
class BaseViewConroller: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
navSetting()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func navSetting() {
navigationController?.navigationBar.backIndicatorImage = #imageLiteral(resourceName: "backArrow").withRenderingMode(.automatic)
navigationController?.navigationBar.backIndicatorTransitionMaskImage = UIImage(named: "backArrow")
navigationItem.backBarButtonItem = UIBarButtonItem(title: "", style:
.plain, target: nil, action: nil)
navigationItem.backBarButtonItem?.tintColor = UIColor(red: 235/255, green: 235/255, blue: 235/255, alpha: 1)
}
}
You can create all your view controller like
class HomeViewController: BaseViewConroller {
...
}

How to Programmatically show UISearchController in UINavigationController's leftbarbuttonitem and hide it after search?

I want to show a UISearchController within UINavigationController, when clicked on UINavigationController's rightbarbuttonitem and hide it when clicked on the button again.
Initially the UINavigationBar will be like this
Later,
The UINavigationBar should look like this, when search is clicked
and further when clicked on close icon, the UINavigationBar should look like in image1.
The code I'm using to show searchcontroller is,
func setUpSearchBar(){
self.searchController = UISearchController(searchResultsController: nil)
self.searchController.searchBar.showsCancelButton = true
var cancelButton: UIButton
let topView: UIView = self.searchController.searchBar.subviews[0] as UIView
for subView in topView.subviews {
if let pvtClass = NSClassFromString("UINavigationButton") {
if subView.isKind(of: pvtClass) {
cancelButton = subView as! UIButton
cancelButton.setTitle("", for: .normal)
cancelButton.tintColor = UIColor.blue
cancelButton.setImage(UIImage(named:"close"), for: .normal)
cancelButton.addTarget(self, action: #selector(pressButton(button:)), for: .touchUpInside)
}
}
}
UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).defaultTextAttributes = [NSFontAttributeName:UIFont(name:"Futura-Medium", size:20)!,NSForegroundColorAttributeName:UIColor(red: 234/255, green: 234/255, blue: 234/255, alpha: 1.0)]
self.searchController.searchResultsUpdater = self
self.searchController.delegate = self
self.searchController.searchBar.delegate = self
self.searchController.hidesNavigationBarDuringPresentation = false
self.searchController.dimsBackgroundDuringPresentation = true
self.searchController.searchBar.tintColor = UIColor(red: 56/255, green: 192/255, blue: 201/255, alpha: 1.0)
self.searchController.searchBar.backgroundColor = UIColor.clear
self.searchController.searchBar.barStyle = .black
// self.navigationItem.titleView = searchController.searchBar
let leftNavBarButton = UIBarButtonItem(customView: self.searchController.searchBar)
self.navigationItem.leftBarButtonItem = leftNavBarButton
self.searchController.searchBar.becomeFirstResponder()
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
self.searchController.searchBar.resignFirstResponder()
self.navigationItem.leftBarButtonItem?.isEnabled = false
self.navigationItem.leftBarButtonItem?.tintColor = .clear
}
func pressButton(button: UIButton) {
searchEvent.isEnabled = true
}
func updateSearchResults(for searchController: UISearchController) {
print(searchController.searchBar.text)
}
But this code shows navigation bar,but when clicked on cancel button, the pressButton event isn't getting triggered?why is that?
You can simply set hidesNavigationBarDuringPresentation property to true which manages to hide Navigation Bar and show a search bar in that area.

How to prevent navbar hiding when keyboard appears ios?

I have an app which has a webview on a storyboard, which loads a registration form in ASP, so when the keyboard or a picker appears, the navbar hides, but never comes back, so I'm not able to go back to the last page.
Here's my code:
import UIKit
class BannerViewController: UIViewController {
#IBOutlet var webView11: UIWebView!
override var preferredStatusBarStyle: UIStatusBarStyle {
return .default
}
override var prefersStatusBarHidden: Bool {
return false
}
override func viewWillAppear(_ animated: Bool) {
self.navigationItem.setHidesBackButton(false, animated: true)
self.setNeedsStatusBarAppearanceUpdate()
self.navigationController?.navigationBar.barTintColor = UIColor(red: 0, green: 0.38, blue: 0.667, alpha: 1)
self.navigationController?.navigationBar.tintColor = UIColor(red: 1, green: 1, blue: 1, alpha: 1)
var titleTextAttributes = [String : AnyObject]();
titleTextAttributes[NSFontAttributeName] = UIFont.systemFont(ofSize: 17, weight: UIFontWeightSemibold)
titleTextAttributes[NSForegroundColorAttributeName] = UIColor(red: 1, green: 1, blue: 1, alpha: 1)
self.navigationController?.navigationBar.titleTextAttributes = titleTextAttributes
}
override func viewDidLoad() {
super.viewDidLoad();
self.navigationController?.navigationBar.barStyle = .default
self.setNeedsStatusBarAppearanceUpdate()
self.navigationController?.setNavigationBarHidden(false, animated: true)
self.webView11.delegate = self;
if let unwrappedwebView11 = URL(string: "http://www.stackoverflow") {
self.webView11.loadRequest(URLRequest(url: unwrappedwebView11))
}
}
}
extension BannerViewController: UIWebViewDelegate {
}
So, it looks like i need to refresh the view or something, as i added a back button out of the webView and when i click and go back to last view, and then i got in again to the webView the navBar doesn´t move anymore

Swift 3 remove line underneath navbar

When my project was in Swift 2, I had this code that worked:
extension UINavigationController {
func hairLine(hide: Bool) {
//hides hairline at the bottom of the navigationbar
for subview in self.navigationBar.subviews {
if subview.isKind(of: UIImageView.self) {
for hairline in subview.subviews {
if hairline.isKind(of: UIImageView.self) && hairline.bounds.height <= 1.0 {
hairline.isHidden = hide
}
}
}
}
}
}
But now something changed and it doesn't work. Not sure if it because of Swift 3, or iOS10, or that I'm now testing with a 7plus vs a 6s, but it no longer works. I would call in it viewWillAppear of the view controller that is being shown. I saw an answer on here saying to use
UINavigationBar.appearance().shadowImage = UIImage()
UINavigationBar.appearance().setBackgroundImage(UIImage(), for: .default)
but that hasn't worked. I tried replacing the content of my old hairLine() with those 2 lines, tried putting them directly in viewWillAppear and viewDidAppear but still doesn't work for me.
Try this
self.navigationController?.navigationBar.setValue(true, forKey: "hidesShadow")
Before:
After:
Code:
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.title = "Hello World"
let navbarColor = UIColor(colorLiteralRed: (247/255), green: (247/255), blue: (247/255), alpha: 1)
let image = UIImage()
navigationController?.navigationBar.setBackgroundImage(image, for: .default)
navigationController?.navigationBar.shadowImage = image
navigationController?.navigationBar.backgroundColor = navbarColor
let statusBarHeight = UIApplication.shared.statusBarFrame.height
let statusBarWidth = UIScreen.main.bounds.size.width
let statusBarView = UIView(frame: CGRect(x: 0, y: 0, width: statusBarWidth, height: statusBarHeight))
statusBarView.backgroundColor = navbarColor
view.addSubview(statusBarView)
}
Try:
self.navigationController?.navigationBar.setBackgroundImage(_:UIImage(),
for: .any,
barMetrics: .default)
self.navigationController?.navigationBar.shadowImage = UIImage()
in viewDidLoad()
Try this
UINavigationBar.appearance().setBackgroundImage(_:
nil,
for: .any,
barMetrics: .default)
UINavigationBar.appearance().shadowImage = nil