Is it possible to have only large titles in the navigation bar? - swift

I want my application to have large titles, however, when the user scrolls, I don't want the regular/normal navigation bar to appear. I just want the large bar to scroll up along with the tableview. Is this possible without making custom views in the navigation bar? I have done it successfully with custom views, but it isn't as fluid and putting a UISearchController inside is a pain.
func createNavController(vc: UIViewController, title: String, image: UIImage, tag: Int) -> UINavigationController {
let navController = UINavigationController(rootViewController: vc)
navController.navigationBar.prefersLargeTitles = true
navController.navigationBar.setBackgroundImage(UIImage(), for: UIBarMetrics.default)
navController.navigationBar.shadowImage = UIImage()
navController.navigationBar.tintColor = .headerColor
navController.tabBarItem = UITabBarItem(title: title, image: image.withRenderingMode(.alwaysTemplate), tag: tag)
navController.navigationBar.topItem?.title = title
navController.navigationBar.titleTextAttributes = [.foregroundColor: UIColor.headerColor, .font: UIFont.customHeaderFont(size: 25)]
navController.navigationBar.largeTitleTextAttributes = [.foregroundColor: UIColor.headerColor, .font: UIFont.customHeaderFont(size: 40)]
// let titleLabel = UILabel()
// titleLabel.text = title
// titleLabel.textColor = .headerColor
// titleLabel.font = UIFont.customHeaderFont(size: navController.navigationBar.frame.height - 5)
// navController.navigationBar.addSubview(titleLabel)
// titleLabel.anchor(top: nil, left: navController.navigationBar.leftAnchor, bottom: nil, right: nil, paddingTop: 0, paddingLeft: 20, paddingBottom: 0, paddingRight: 0, width: 0, height: 0)
// titleLabel.centerYAnchor.constraint(equalTo: navController.navigationBar.centerYAnchor).isActive = true
return navController
}

Use my extension iOS 13 Swift 5 tested
extension UIViewController {
func configureNavigationBar(largeTitleColor: UIColor, backgoundColor: UIColor, tintColor: UIColor, title: String, preferredLargeTitle: Bool) {
if #available(iOS 13.0, *) {
let navBarAppearance = UINavigationBarAppearance()
navBarAppearance.configureWithOpaqueBackground()
navBarAppearance.largeTitleTextAttributes = [.foregroundColor: largeTitleColor]
navBarAppearance.titleTextAttributes = [.foregroundColor: largeTitleColor]
navBarAppearance.backgroundColor = backgoundColor
navigationController?.navigationBar.standardAppearance = navBarAppearance
navigationController?.navigationBar.compactAppearance = navBarAppearance
navigationController?.navigationBar.scrollEdgeAppearance = navBarAppearance
navigationController?.navigationBar.prefersLargeTitles = preferredLargeTitle
navigationController?.navigationBar.isTranslucent = false
navigationController?.navigationBar.tintColor = tintColor
navigationItem.title = title
} else {
// Fallback on earlier versions
navigationController?.navigationBar.barTintColor = backgoundColor
navigationController?.navigationBar.tintColor = tintColor
navigationController?.navigationBar.isTranslucent = false
navigationItem.title = title
}
}}
How to use:
configureNavigationBar(largeTitleColor: .yourColor, backgoundColor: .yourColor, tintColor: .yourColor, title: "yuorTitle", preferredLargeTitle: true)
Set ViewController-based status bar...... to NO in info.plist if you want light Content
If you don't want largeTitles set it to false
for tranlsucent change navBarAppearance.configureWithOpaqueBackground() in:
navBarAppearance.configureWithDefaultBackground()
navigationController?.navigationBar.isTranslucent = true
in the call set background color to .clear
UPDATE: If you want to start with navigation controller and large Titles at first controller, don't forget to set launch controller in Scene Delegate like this:
guard let windowScene = (scene as? UIWindowScene) else { return }
window = UIWindow(windowScene: windowScene)
window?.makeKeyAndVisible()
let vC = UINavigationController(rootViewController: YourFirstViewController())
window?.rootViewController = vC
hope this help :)

You can probe create your custom navigation controller and called in your view controllers; is more easy, customize the native navigation controller is hard, but you can do it scouring subviews in the natives elements.

Related

UINavigation custom back button image not working in iOS 15

I want to apply UINavigation custom background image and back button image also for iOS 14 everything is working fine but as I try to run the app on iOS 15 back button image not working instead it's showing the default back button which I want to replace with custom back button image I am using below code
if #available(iOS 15.0, *) {
let appearance = UINavigationBarAppearance()
appearance.configureWithTransparentBackground()
appearance.backgroundImage = image
appearance.setBackIndicatorImage(backButtonImage, transitionMaskImage: backButtonImage)
if Locale.current.languageCode == "fr" {
appearance.titleTextAttributes = [ NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: 14), NSAttributedString.Key.foregroundColor: UIColor(hexString: "#231F20")]
} else {
appearance.titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor(hexString: "#231F20")]
}
navigationItem.standardAppearance = appearance
navigationItem.scrollEdgeAppearance = appearance
} else {
self.navigationController?.navigationBar.setBackgroundImage(image, for: .default)
self.navigationController?.navigationBar.backIndicatorImage = backButtonImage
self.navigationController?.navigationBar.backIndicatorTransitionMaskImage = backButtonImage
if Locale.current.languageCode == "fr" {
self.navigationController?.navigationBar.titleTextAttributes = [ NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: 14), NSAttributedString.Key.foregroundColor: UIColor(hexString: "#231F20")]
} else {
self.navigationController?.navigationBar.titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor(hexString: "#231F20")]
}
}
Sharing with you a common function I have made in a BaseViewController which is the superclass of all my View Controllers.
I Simply call the addBackButton function from viewDidLoad from any of the VC I want to add the back button.
It also handles the back navigation automatically. (takes care if you have presented or pushed a vc)
func addBackButton(tint : UIColor? = nil, backImage : UIImage? = Constants.Images.kImageForBackNavigation){
let buttonForBack = UIButton(type: .custom)
var tintColorForImage = UIColor.white
if tint != nil {
tintColorForImage = tint!
}
let image = backImage!.withRenderingMode(.alwaysTemplate)
buttonForBack.setImage(image, for: .normal)
buttonForBack.imageView?.tintColor = tintColorForImage
buttonForBack.frame = CGRect(x: 0, y: 0, width: 30, height: 30)
buttonForBack.addTarget(self, action: #selector(BaseViewController.closeViewController), for: .touchUpInside)
let barButtonItemForClose = UIBarButtonItem(customView: buttonForBack)
self.navigationItem.setLeftBarButton(barButtonItemForClose, animated: false)
}
#objc func closeViewController(){
if self == self.navigationController?.children.first {
DispatchQueue.main.async {
self.navigationController?.dismiss(animated: true, completion: nil);
}
}
else{
DispatchQueue.main.async {
self.navigationController?.popViewController(animated: true)
}
}
}

iOS 13: large navigation bar not using bar tint color (defaults to white) [duplicate]

Pre-conditions to reproduce the problem:
Xcode 11 beta + iOS 13 (latest version until Jun. 12 2019)
The navigation bar is in Large text mode
Specify the colour of navigation bar.
The status bar will remain in white in a real device, above the green navigation bar.
Solutions I tried:
Revert it back to iOS12 will solve it, but we will encounter iOS13 eventually...
disabling the large text mode will solve it...
hide the status bar will fix it, but it will cause status text overlapping with navigation bar item.
Any ideas? appreciate any help.
No hacks or funkiness required here. The key is defining the desired appearance and setting this value on BOTH the nav bar's standardAppearance AND its scrollEdgeAppearance. I have the following in the init for my base navigation controller subclass for my entire app:
if #available(iOS 13.0, *) {
let navBarAppearance = UINavigationBarAppearance()
navBarAppearance.configureWithOpaqueBackground()
navBarAppearance.titleTextAttributes = [.foregroundColor: UIColor.white]
navBarAppearance.largeTitleTextAttributes = [.foregroundColor: UIColor.white]
navBarAppearance.backgroundColor = <insert your color here>
navigationBar.standardAppearance = navBarAppearance
navigationBar.scrollEdgeAppearance = navBarAppearance
}
If the problem is that you'd like to give the navigation bar a color when the large title is showing, use the new UINavigationBarAppearance class.
let app = UINavigationBarAppearance()
app.backgroundColor = .blue
self.navigationController?.navigationBar.scrollEdgeAppearance = app
On iOS 13, navigation bars using large title have a transparent color per Apple human interface guidelines. See more infos here:
In iOS 13 and later, a large title navigation bar doesn’t include a background material or shadow by default. Also, a large title transitions to a standard title as people begin scrolling the content
Universal code
let navBarAppearance = UINavigationBarAppearance()
navBarAppearance.configureWithOpaqueBackground()
navBarAppearance.backgroundColor = // your color
navBarAppearance.shadowImage = nil // line
navBarAppearance.shadowColor = nil // line
UINavigationBar.appearance(whenContainedInInstancesOf: [UINavigationController.self]).standardAppearance = navBarAppearance
UINavigationBar.appearance(whenContainedInInstancesOf: [UINavigationController.self]).scrollEdgeAppearance = navBarAppearance
Objective C Solutions and iOS 13
UINavigationBarAppearance* navBarAppearance = [self.navigationController.navigationBar standardAppearance];
[navBarAppearance configureWithOpaqueBackground];
navBarAppearance.titleTextAttributes = #{NSForegroundColorAttributeName:TitleColor};
navBarAppearance.largeTitleTextAttributes = #{NSForegroundColorAttributeName: TitleColor};
navBarAppearance.backgroundColor = TopColor;
self.navigationController.navigationBar.standardAppearance = navBarAppearance;
self.navigationController.navigationBar.scrollEdgeAppearance = navBarAppearance;
my navigationBar extension, iOS 13 Swift 5
extension UIViewController {
func configureNavigationBar(largeTitleColor: UIColor, backgoundColor: UIColor, tintColor: UIColor, title: String, preferredLargeTitle: Bool) {
if #available(iOS 13.0, *) {
let navBarAppearance = UINavigationBarAppearance()
navBarAppearance.configureWithOpaqueBackground()
navBarAppearance.largeTitleTextAttributes = [.foregroundColor: largeTitleColor]
navBarAppearance.titleTextAttributes = [.foregroundColor: largeTitleColor]
navBarAppearance.backgroundColor = backgoundColor
navigationController?.navigationBar.standardAppearance = navBarAppearance
navigationController?.navigationBar.compactAppearance = navBarAppearance
navigationController?.navigationBar.scrollEdgeAppearance = navBarAppearance
navigationController?.navigationBar.prefersLargeTitles = preferredLargeTitle
navigationController?.navigationBar.isTranslucent = false
navigationController?.navigationBar.tintColor = tintColor
navigationItem.title = title
} else {
// Fallback on earlier versions
navigationController?.navigationBar.barTintColor = backgoundColor
navigationController?.navigationBar.tintColor = tintColor
navigationController?.navigationBar.isTranslucent = false
navigationItem.title = title
}
}}
How to use:
configureNavigationBar(largeTitleColor: .yourColor, backgoundColor: .yourColor, tintColor: .yourColor, title: "YourTitle", preferredLargeTitle: true)
Set ViewController-based status bar...... to NO in info.plist if you want light Content
If you don't want largeTitles set it to false
Tested on iOS 13, hope this help :)
If you want to remove the underline below the nav bar
if #available(iOS 13.0, *) {
let navBarAppearance = UINavigationBarAppearance()
navBarAppearance.configureWithOpaqueBackground()
navBarAppearance.titleTextAttributes = [.foregroundColor: UIColor.white]
navBarAppearance.largeTitleTextAttributes = [.foregroundColor: UIColor.white]
navBarAppearance.backgroundColor = <yourColor>
navBarAppearance.backgroundImage = UIImage()
navBarAppearance.shadowImage = UIImage()
navBarAppearance.shadowColor = .clear
self.navigationController?.navigationBar.standardAppearance = navBarAppearance
self.navigationController?.navigationBar.scrollEdgeAppearance = navBarAppearance
}
For iOS 13 I was having a problem with the bar's shadow line showing up. Setting the Bars shadow image to nil solved that issue.
Before
func configureNavigation() {
let navBarAppearance = UINavigationBarAppearance()
navBarAppearance.configureWithOpaqueBackground()
navBarAppearance.largeTitleTextAttributes = [.foregroundColor: UIColor.myColor,
.font: UIFont(name: "MyFont", size: 42)!]
navBarAppearance.backgroundColor = .white
navigationController?.navigationBar.isTranslucent = false
navigationController?.navigationBar.scrollEdgeAppearance = navBarAppearance
}
After
func configureNavigation() {
let navBarAppearance = UINavigationBarAppearance()
navBarAppearance.configureWithOpaqueBackground()
navBarAppearance.largeTitleTextAttributes = [.foregroundColor: UIColor.myColor,
.font: UIFont(name: "MyFont", size: 42)!]
navBarAppearance.backgroundColor = .white
navBarAppearance.shadowColor = nil
navigationController?.navigationBar.isTranslucent = false
navigationController?.navigationBar.scrollEdgeAppearance = navBarAppearance
}
Fully workable code:
let navigationBarAppearace = UINavigationBar.appearance()
navigationBarAppearace.tintColor = .tintColor
navigationBarAppearace.barTintColor = .barTintColor
navigationBarAppearace.titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.tintColor]
if #available(iOS 13.0, *) {
let navBarAppearance = UINavigationBarAppearance()
navBarAppearance.configureWithOpaqueBackground()
navBarAppearance.titleTextAttributes = [.foregroundColor: UIColor.tintColor]
navBarAppearance.largeTitleTextAttributes = [.foregroundColor: UIColor.tintColor]
navBarAppearance.backgroundColor = <insert your color here>
navigationBarAppearace.standardAppearance = navBarAppearance // have a look here ;)
navigationBar.scrollEdgeAppearance = navBarAppearance
}
Good luck all, Peace!
Thanks to Mike and Hans's answer. My case is half transparent status bar and nav bar with alpha 0.5. iOS13 seems complicated. Below is my test result, will work if you want transparent for both.
if #available(iOS 13.0, *) {
let navBarAppearance = UINavigationBarAppearance()
// This only set top status bar as transparent, not the nav bar.
navBarAppearance .configureWithTransparentBackground()
// This set the color for both status bar and nav bar(alpha 1).
navBarAppearance.backgroundColor = UIColor.red.withAlphaComponent(0.5)
navigationController?.navigationBar.standardAppearance = navBarAppearance
navigationController?.navigationBar.scrollEdgeAppearance = navBarAppearance
// Nav bar need sets to translucent for both nav bar and status bar to be translucent.
navigationController?.navigationBar.isTranslucent = true
// // Need to reset nav bar's color to make it clear to display navBarAppearance's color
navigationController?.navigationBar.backgroundColor = UIColor.clear
}
I had a similar problem when updating one of my apps to be more iOS 13 compatible. As Hans mentioned above, the large titles are transparent by default. If you are a heavy Storyboard user as I am, there's another setting in the side bar that's easy to turn on.
If you click on your nav bar in the story board, it usually defaults to selecting the Navigation Item, and you won't get any customization options. Select the Navigation Bar option above it, and then you are able to choose a custom background color of whatever you want over in the Inspector on the right.
I've discovered that with storyboards you have to fake the nav bar (only really works with opaque nav bars, assuming your green is opaque). The best way I found was to create a placeholder view (purple) that fits the safe area insets, and then add a fake view behind the nav bar (cyan/blue) that is the height remaining. Works for my project, but yeah it's a bit of a hack.
Edit: This is mainly for LaunchScreen.storyboard where you can't use a custom view controller class.
Swift 5
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
let userInterfaceStyle = traitCollection.userInterfaceStyle
modeDetect(userInterfaceStyle: userInterfaceStyle)
}
override func viewDidAppear(_ animated: Bool) {
navigationController?.navigationBar.barStyle = .black
navigationController?.navigationBar.titleTextAttributes = [.foregroundColor: UIColor.white]
}
func modeDetect(userInterfaceStyle: UIUserInterfaceStyle) {
switch userInterfaceStyle {
case .light:
navigationController?.navigationBar.barTintColor = .systemPink
case .dark:
navigationController?.navigationBar.barTintColor = .systemBackground
default:
break
}
}
Call this function with a proper argument.
This code is working properly.
open func showNavigationBar(large: Bool,
animated: Bool,
isTransparabar: Bool,
titleColor: UIColor,
barBackGroundColor: UIColor,
fontSize: CGFloat) {
navigationController?.navigationBar.barTintColor = barBackGroundColor
navigationController?.navigationBar.backgroundColor = barBackGroundColor
navigationController?.navigationBar.isTranslucent = true
self.navigationController?.setNavigationBarHidden(false, animated: animated)
if large {
self.navigationController?.navigationBar.prefersLargeTitles = true
if #available(iOS 13.0, *) {
let appearance = UINavigationBarAppearance()
appearance.backgroundColor = barBackGroundColor
appearance.titleTextAttributes = [.foregroundColor: titleColor]
appearance.largeTitleTextAttributes = [NSAttributedString.Key.foregroundColor: titleColor]
navigationController?.navigationBar.standardAppearance = appearance
navigationController?.navigationBar.compactAppearance = appearance
navigationController?.navigationBar.scrollEdgeAppearance = appearance
} else {
self.navigationController?.navigationBar.largeTitleTextAttributes = [NSAttributedString.Key.foregroundColor: titleColor]
}
} else {
self.navigationController?.navigationBar.prefersLargeTitles = false
self.navigationController?.navigationBar.titleTextAttributes = [NSAttributedString.Key.foregroundColor: titleColor!]
}
}
The following Objective-C code made iOS 13 navigation bar behave like the previous version for me:
if (#available(iOS 13.0, *)) {
// Setup iOS 13 navigation bar
sharedSelector.navigationBar.scrollEdgeAppearance = sharedSelector.navigationBar.standardAppearance;
} else {
// Fallback on earlier versions
}
I just turn on translucent in storyboard
#mohmmad alabid's answer would need to be applied to each view controller seperately, if you want a generic objective-c solution put this in your app delegate inside the didFinishLaunchingWithOptions function.
if (#available(iOS 13.0, *)) {
UINavigationBarAppearance* navBarAppearance = [[UINavigationBarAppearance alloc] init];
[navBarAppearance configureWithOpaqueBackground];
navBarAppearance.titleTextAttributes = #{NSForegroundColorAttributeName:NAVBAR_TEXT_COLOR};
navBarAppearance.largeTitleTextAttributes = #{NSForegroundColorAttributeName: NAVBAR_TEXT_COLOR};
navBarAppearance.backgroundColor = NAVBAR_COLOR;
[[UINavigationBar appearance] setStandardAppearance: navBarAppearance];
[[UINavigationBar appearance] setScrollEdgeAppearance: navBarAppearance];
}
Mike's solution is great.
I offer an alternative approach to change the UINavigationBar color which applies to any iOS version.
We are basically going to exploit the fact that we can set an Image as the UINavigationBar's background.
FIRST
Add an extension to generate a UIImage from any UColor. Note that you can also also write an extension later to generate UIColor from hexadecimals or other formats if you want.
extension UIColor {
func image(_ size: CGSize = CGSize(width: 1, height: 1)) -> UIImage {
return UIGraphicsImageRenderer(size: size).image { rendererContext in
self.setFill()
rendererContext.fill(CGRect(origin: .zero, size: size))
}
}
}
Thanks #neoneye for this great UIColor extension :)
SECOND
Now we get down to business:
private func setupNavigationBarAppearance(navBar: UINavigationBar) {
navBar.isTranslucent = false
let navBarColorImage = UIColor.blue.image()
navBar.setBackgroundImage(navBarColorImage, for: .default)
navBar.tintColor = UIColor.white
}
Because we've setup the opaque colored image as the background, we do not need to check for iOS 13.
I hope this help some folks to customize their NavBars.
Cheers!

iOS13 Navigation bar large titles not covering status bar

On ios13, with iphone x, the large title navigation does not cover the status bar however when scrolling and transitioning into the traditional nav bar, it works perfectly. This doesn't affect devices without the notch.
Large titles
Traditional navigation bar
It's all embedded within a navigation controller so i'm lost as to why this is happening. Cheers
The official way to customize the UINavigationBar, pre iOS 13, is this:
// text/button color
UINavigationBar.appearance().tintColor = .white
// background color
UINavigationBar.appearance().barTintColor = .purple
// required to disable blur effect & allow barTintColor to work
UINavigationBar.appearance().isTranslucent = false
iOS 13 has changed how navigation bars work, so you'll need to do things slightly differently to support both old & new:
if #available(iOS 13.0, *) {
let appearance = UINavigationBarAppearance()
appearance.backgroundColor = .purple
appearance.titleTextAttributes = [.foregroundColor: UIColor.white]
appearance.largeTitleTextAttributes = [.foregroundColor: UIColor.white]
UINavigationBar.appearance().tintColor = .white
UINavigationBar.appearance().standardAppearance = appearance
UINavigationBar.appearance().compactAppearance = appearance
UINavigationBar.appearance().scrollEdgeAppearance = appearance
} else {
UINavigationBar.appearance().tintColor = .white
UINavigationBar.appearance().barTintColor = .purple
UINavigationBar.appearance().isTranslucent = false
}
Use my extension iOS 13 Swift 5 tested
extension UIViewController {
func configureNavigationBar(largeTitleColor: UIColor, backgoundColor: UIColor, tintColor: UIColor, title: String, preferredLargeTitle: Bool) {
if #available(iOS 13.0, *) {
let navBarAppearance = UINavigationBarAppearance()
navBarAppearance.configureWithOpaqueBackground()
navBarAppearance.largeTitleTextAttributes = [.foregroundColor: largeTitleColor]
navBarAppearance.titleTextAttributes = [.foregroundColor: largeTitleColor]
navBarAppearance.backgroundColor = backgoundColor
navigationController?.navigationBar.standardAppearance = navBarAppearance
navigationController?.navigationBar.compactAppearance = navBarAppearance
navigationController?.navigationBar.scrollEdgeAppearance = navBarAppearance
navigationController?.navigationBar.prefersLargeTitles = preferredLargeTitle
navigationController?.navigationBar.isTranslucent = false
navigationController?.navigationBar.tintColor = tintColor
navigationItem.title = title
} else {
// Fallback on earlier versions
navigationController?.navigationBar.barTintColor = backgoundColor
navigationController?.navigationBar.tintColor = tintColor
navigationController?.navigationBar.isTranslucent = false
navigationItem.title = title
}
}}
How to use:
configureNavigationBar(largeTitleColor: .yourColor, backgoundColor: .yourColor, tintColor: .yourColor, title: "yuorTitle", preferredLargeTitle: true)
Set ViewController-based status bar...... to NO in info.plist if you want light Content
If you don't want largeTitles set it to false
for tranlsucent change navBarAppearance.configureWithOpaqueBackground() in:
navBarAppearance.configureWithDefaultBackground()
navigationController?.navigationBar.isTranslucent = true
in the call set background color to .clear
UPDATE:
If you want to start with navigation controller and large Titles at first controller, don't forget to set launch controller in Scene Delegate like this:
guard let windowScene = (scene as? UIWindowScene) else { return }
window = UIWindow(windowScene: windowScene)
window?.makeKeyAndVisible()
let vC = UINavigationController(rootViewController: YourFirstViewController())
window?.rootViewController = vC
hope this help :)
For full application navigation bar support please add this extension inside your code.
import UIKit
extension UIViewController {
open func showNavigationBar(_ large: Bool,
_ animated: Bool,
titleColor: UIColor,
barTintColor: UIColor,
fontSize: CGFloat) {
navigationController?.navigationBar.barTintColor = barTintColor
navigationController?.navigationBar.backgroundColor = barTintColor
navigationController?.navigationBar.isTranslucent = true
self.navigationController?.setNavigationBarHidden(false, animated: animated)
if large {
self.navigationController?.navigationBar.prefersLargeTitles = true
if #available(iOS 13.0, *) {
let appearance = UINavigationBarAppearance()
appearance.backgroundColor = barTintColor
appearance.titleTextAttributes = [.foregroundColor: titleColor]
appearance.largeTitleTextAttributes = [NSAttributedString.Key.foregroundColor: titleColor,
NSAttributedString.Key.font: UIFont(resource: R.font.robotoMedium, size: fontSize)!]
navigationController?.navigationBar.standardAppearance = appearance
navigationController?.navigationBar.compactAppearance = appearance
navigationController?.navigationBar.scrollEdgeAppearance = appearance
} else {
self.navigationController?.navigationBar.largeTitleTextAttributes = [NSAttributedString.Key.foregroundColor: titleColor,
NSAttributedString.Key.font: UIFont(resource: R.font.robotoMedium, size: fontSize)!]
}
} else {
self.navigationController?.navigationBar.prefersLargeTitles = false
self.navigationController?.navigationBar.titleTextAttributes = [NSAttributedString.Key.foregroundColor: titleColor,
NSAttributedString.Key.font: UIFont(resource: R.font.robotoMedium, size: 20.0)!]
}
}
}
And Then call this method simply
self.showNavigationBar(true, true, titleColor: UIColor.blue, barTintColor: UIColor.red, fontSize: 32.0)

Use background image on UISearchController iOS 11

I'm implementing an UISearchController to my UITableView but I'm struggling with the customization for iOS 11. My navigation bar is using a gradient image background that I want the search controller to match, but I haven't found a way to set the background image for UISearchController. It works perfectly on UISearchController as a TableHeaderView, but in iOS 11 barely any customization is passed on.
Current outcome:
Desired outcome:
This is the code I'm using: (called on viewDidLoad)
private func setupSearchController() {
let searchController = UISearchController(searchResultsController: nil)
// Convert CAGradientLayer to UIImage
let gradient = Color.blue.gradient
gradient.frame = searchController.searchBar.bounds
UIGraphicsBeginImageContext(gradient.bounds.size)
gradient.render(in: UIGraphicsGetCurrentContext()!)
let gradientImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
// Setup the Search Controller
searchController.searchBar.backgroundImage = gradientImage
searchController.searchBar.isTranslucent = false
searchController.searchResultsUpdater = self
searchController.hidesNavigationBarDuringPresentation = false
searchController.dimsBackgroundDuringPresentation = false
searchController.obscuresBackgroundDuringPresentation = false
searchController.searchBar.placeholder = "Search by transaction name"
searchController.searchBar.tintColor = Color.custom(hexString: "FAFAFA", alpha: 1).value
definesPresentationContext = true
searchController.searchBar.delegate = self
// Implement Search Controller
if #available(iOS 11.0, *) {
navigationItem.searchController = searchController
navigationItem.hidesSearchBarWhenScrolling = false
navigationController?.navigationBar.setBackgroundImage(gradientImage, for: .default)
} else {
tableView.tableHeaderView = searchController.searchBar
}
}
Thanks to Krunal's answer I was able to find a decent solution after searching for quite some time.
This is how I came about implementing the background-image for iOS 11:
// Implement Search Controller
if #available(iOS 11.0, *) {
if let navigationBar = self.navigationController?.navigationBar {
navigationBar.barTintColor = UIColor(patternImage: gradientImage!)
}
if let textField = searchController.searchBar.value(forKey: "searchField") as? UITextField {
if let backgroundview = textField.subviews.first {
backgroundview.backgroundColor = UIColor.white
backgroundview.layer.cornerRadius = 10;
backgroundview.clipsToBounds = true;
}
}
navigationItem.searchController = searchController
navigationItem.hidesSearchBarWhenScrolling = false
} else {
tableView.tableHeaderView = searchController.searchBar
}
You can add a CustomView for this.
Use CustomView to add your searchBar to it, and then add this customView to your ViewController.
Now you can easily set the background of this customView as:
//if customView is named as customView
let backgroundImage = UIImageView(frame: UIScreen.mainScreen().bounds)
backgroundImage.image = UIImage(named: "background.png")
self.customView.insertSubview(backgroundImage, atIndex: 0)
Swift 5, iOS 15
Considering searchController is a property of your class (vc most likely), navigation vc is not nil, "gradient" image is your asset with a gradient mix of some colors.
Put this code in your viewDidLoad to achieve a gradient navigation bar and a search field with a white background color.
let appearance = UINavigationBarAppearance()
appearance.backgroundImage = UIImage(named: "gradient")?.resizableImage(withCapInsets: .zero,
resizingMode: .stretch)
navigationController?.navigationBar.scrollEdgeAppearance = appearance
navigationController?.navigationBar.standardAppearance = appearance
searchController = UISearchController(searchResultsController: nil)
/// Trick to have a white searchTextField background color, weird but it works.
searchController?.searchBar.searchTextField.borderStyle = .none
searchController?.searchBar.searchTextField.layer.cornerRadius = 10
searchController?.searchBar.searchTextField.layer.cornerCurve = .continuous
searchController?.searchBar.searchTextField.backgroundColor = .white
navigationItem.searchController = searchController
Result:
Moving back from current vc you may want to reset your navigation bar to the default settings. For this purpose you may try to create UINavigationViewController extension with a handy function:
extension UINavigationController {
func resetToDefaultAppearance() {
let appearance = UINavigationBarAppearance()
appearance.configureWithDefaultBackground()
navigationBar.standardAppearance = appearance
navigationBar.scrollEdgeAppearance = appearance
navigationBar.standardAppearance = appearance
navigationBar.compactScrollEdgeAppearance = appearance
}
}
Then call it in your viewWillDisappear:
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
navigationController?.resetToDefaultAppearance()
}

Swift, Add a navigation controller in custom activity indicator

My Custom Activity indicator is not overlapping Navigation controller.
Below is my code
func showActivityIndicator(uiView: UIView) {
container.frame = uiView.frame
container.center = uiView.center
container.backgroundColor = UIColorFromHex(0xffffff, alpha: 0.1)
var loadingView: UIView = UIView()
loadingView.frame = CGRectMake(0, 0, self.view.frame.width, self.view.frame.height)
loadingView.center = uiView.center
loadingView.backgroundColor = UIColorFromHex(0x444444, alpha: 0.5)
loadingView.clipsToBounds = true
loadingView.layer.cornerRadius = 10
var imageData = NSData(contentsOfURL: NSBundle.mainBundle()
.URLForResource("synch-loader", withExtension: "gif")!)
let try = UIImage.animatedImageWithData(imageData!)
var imageView = UIImageView(image: try)
imageView.center = uiView.center
imageView.frame = CGRect(x: uiView.frame.width/4, y: uiView.frame.height/2, width: 500, height: 15)
loadingView.addSubview(imageView)
container.addSubview(loadingView)
uiView.addSubview(container)
actInd.startAnimating()
}
func navigationHandling()
{
if self.navigationController != nil {
self.navigationController?.navigationBar.tintColor = utility.uicolorFromHex(0x70B420)
self.navigationController?.navigationBar.barTintColor = utility.uicolorFromHex(0x70B420)
self.navigationController?.navigationBarHidden = false
self.navigationItem.hidesBackButton = true
}
sortingBtn = UIBarButtonItem(image: sortingImg, style: UIBarButtonItemStyle.Done, target: self, action: Selector("sortingPressed:"))
menuBtn = UIBarButtonItem(image: menuImg, style: UIBarButtonItemStyle.Plain, target: self, action : nil)
sortingBtn.tintColor = UIColor.whiteColor()
menuBtn.tintColor = UIColor.whiteColor()
var buttons : NSArray = [menuBtn,sortingBtn]
self.navigationItem.rightBarButtonItems = buttons as [AnyObject]
self.navigationItem.setRightBarButtonItems([menuBtn,sortingBtn], animated: true)
networkLabel.hidden = true
}
I just want to overlap the view on navigation controller so that it don't looks ugly.
I appreciate help!
let appDelegate = UIApplication.sharedApplication().delegate as? AppDelegate
let window = appDelegate?.window
window.addSubview("yourActivityIndicator")
Here add the activity indicator to the window, or pass the window in as the view.
let appDelegate = UIApplication.sharedApplication().delegate as? AppDelegate
let window = appDelegate?.window
showActivityIndicator(window)
The uiView you're passing as parameter to this method
func showActivityIndicator(uiView: UIView)
is your ViewController's view or your UINavigationController's view?
Because if it's your UIViewController's view your custom loading will take it's size and origin, that is under your NavigationBar