My goal is to create a UI that looks like this
The only way that I could think of is to embed a navigationController on the UIViewController then add UIView
Storyboard
Code - ProfileViewController
class ProfileViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
navigationBarColor()
}
func navigationBarColor() {
navigationController?.navigationBar.backgroundColor = UIColor(red:0.91, green:0.04, blue:0.51, alpha:1.0)
navigationController?.navigationBar.shadowImage = UIImage()
navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
}
}
Result
Is my approach correct? or do I need to use a different method to achieve this result?
The best way to do this is to make the navigationBar invisible basically. Here is what I did to achieve the look you want:
Step 1:
Add the navigation controller and a view controller and hold control and drag from the navigation controller to the view controller and select root view controller(which i am pretty sure you have already done). Also, drag and drop a UIBarButtonItem onto the navigationBar in the view controller, not the navigationBar in the navigation controller.
Step 2:
Subclass the navigation controller and the view controller, in my example, mine are called CustomNavController.swift and MainVC.swift. In the storyboard, set them as the class of the controllers.
Step 3:
In the class you made for the view controller, set the code in the viewDidLoad to change the background color.
import Foundation
import UIKit
class MainVC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor(red: 231/255, green: 11/255, blue: 129/255, alpha: 1)
}
}
And in the navigation controller class, add this code.
import UIKit
class CustomNavController: UINavigationController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.navigationBar.setBackgroundImage(UIImage(), for: .default)
self.navigationBar.shadowImage = UIImage()
self.navigationBar.isTranslucent = true
self.navigationBar.tintColor = .white
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
}
The Result:
Since you are using a navigation controller, you have to set the status bar style to lightContent in the navigation controller subclass like shown above. If you have other view controller that you want the status bar to be black in, you will have to implement the method preferredStatusBarStyle in the class and return .default unless, if the view controller has a navigation controller associated with it, the you would have to implement preferredStatusBarStyle in the navigation controller subclass like I showed in my example. If you have any questions feel free to leave a comment and I will answer when I can.
You can subclass navigation bar, but with that amount of size, i think it's not a good approach. What you are doing seems ok. It's a solution.
Your approach will work. To match your Sketch mockup as closely as possible, here are a few tips:
UINavigationBar's background color should be set using the barTintColor property. This will give the status bar the same background color.
Set the UINavigationBar's barStyle property to black. This will set the status bar's content color to white.
You might notice how the navigation bar's color is slightly different from the view you created beneath it. This is because UINavigationBar is translucent by default, so the background color has a reduced alpha value. You can set the UINavigationBar property isTranslucent to false to fix this.
An alternative approach (without UINavigationController) would involve creating a simple UIView to use as the status bar background, as shown here: https://stackoverflow.com/a/43264566/5223633.
First step, add this 3 lines of codes in your viewDidLoad methods of your controller class:
navigationController?.navigationBar.barTintColor = UIColor(red:0.91, green:0.04, blue:0.51, alpha:1.0)
navigationController?.navigationBar.tintColor = UIColor.white
UIApplication.shared.statusBarStyle = .lightContent
And then, select your info.plist file. When it's opened, add a row by right clicking on it. Give the key name:
View controller-based status bar appearance
and set it's value into:
NO
as boolean value.
see this info.plist screenshot example
Then run it.
You can create custom viewcontroller with Xib file after that load and add its view inside your navigation bar. Hide back button if required and update navigationBar height
accordingly
navigationItem.hidesBackButton = true
navigationController?.navigationBar.frame.size.height = 100
guard let yourCustomView = UINib(nibName: "yourCustomXib", bundle: nil).instantiate(withOwner: nil, options: nil).first as? YourCustomView else {
fatalError("Missing yourCustomXib")
}
navigationController?.navigationBar.addSubview(yourCustomView)
Related
How to add view above navigation bar?
I have a custom navigation controller and I want to present a view above nav bar (like on the screen), so it should be visible on other ViewControllers
Would be great if the solution will be on storyboard.
Tried to add on UIWindow did't help.
Swift 4.2, Xcode 10+
Okay, from what I can tell (via your comment reply, though it still isn't 100% clear), the best solution to your question would be to make the navigation bar transparent, such that you can see any navigationController-presented view controllers underneath it. For this, I'd suggest the following extension to UIViewController:
extension UIViewController {
func setupTransparentNavigationBarWithBlackText() {
setupTransparentNavigationBar()
//Status bar text and back(item) tint to black
self.navigationController?.navigationBar.barStyle = .default
self.navigationController?.navigationBar.tintColor = .black
}
func setupTransparentNavigationBarWithWhiteText() {
setupTransparentNavigationBar()
//Status bar text and back(item) tint to white
self.navigationController?.navigationBar.barStyle = .blackTranslucent
self.navigationController?.navigationBar.tintColor = .white
}
func setupTransparentNavigationBar() {
self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
self.navigationController?.navigationBar.shadowImage = UIImage()
self.navigationController?.navigationBar.backgroundColor = .clear
self.navigationController?.navigationBar.isTranslucent = true
}
}
Using either of the first two methods in viewWillAppear of your UIViewController subclasses will let you make the navigation bar completely transparent with the statusBar text + wifi/battery indicators black or white as desired. From this, you can then display anything under the navigation bar by pinning your constraints to view.bounds.topAnchor. E.g. for a transparent navigation controller with white statusBar text:
class YourViewController: UIViewController {
override func viewWillAppear(_ animated: Bool) {
setupTransparentNavigationBarWithWhiteText()
}
}
I'm trying to set the tab bar to have a different background image on each view controller.
class CharacterVC: UIViewController {
var tabBarApparence = UITabBar.appearance()
override func viewDidLoad() {
super.viewDidLoad()
tabBarApparence.backgroundImage = UIImage(named: "BlueTB") //Loaded from Image Asset
}
This works fine and changes it to blue in that view, however when I go to the next view it stays the blue colour and doesn't change to the red colour which I programmed in with this code:
class AnonVC: UIViewController {
var tabBarApparence = UITabBar.appearance()
override func viewDidLoad() {
super.viewDidLoad()
tabBarApparence.backgroundImage = UIImage(named: "RedTabBar")
// addtional code here
}
I have an additional 2 view controllers, one should display the green version of the image and the other the purple version of the image.
Any suggestions which could fix this?
If you want to change appearance of TabBar in a view controller is very easy. You can this in function viewDidLoad or viewWillAppear. The code is the next:
// Set color of titles and icons in tabBar
self.tabBarController?.tabBar.tintColor = UIColor.redColor()
// Set color of background tabBar
self.tabBarController?.tabBar.barTintColor = UIColor.blueColor()
Replace code to viewWillAppear()
Better set backgroundImage to tabBar, not to UITabBar.appearance()
I want to set the UINavigationBar color per view controller, not in the app delegate, as that would be done like this.
UINavigationBar.appearance().backgroundColor = UIColor.whiteColor()
UINavigationBar.appearance().translucent = false
I have looked around and just cant find how to do this.I tried doing it like this but it did not work:
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.navigationBar.barTintColor = UIColor.whiteColor()
self.navigationController?.navigationBar.tintColor = UIColor.blackColor()
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem()
}
How do I set the color dependent on the view controller and not globally?
From my understanding, you will need to have code in each view controller to set the nav bar colour. Try adding this code to the viewDidLoad for each of your view controllers:
if let navController = self.navigationController {
navController.navigationBar.tintColor = self.view.tintColor
}
This will make the nav bar's tint colour whatever the view controller's tint colour is, but you can obviously change this to any colour you want.
The beauty of this is you can literally just copy paste this without having to change anything, so it is really easy to implement across multiple view controllers (as there are no specific references to the name of the view controller).
I hope this helps.
I am having troubles setting the self.navigationItem.titleView, could someone please help me catch my mistake.
import Foundation
class CustomNavigationController: UINavigationController
{
override func viewDidLoad() {
let logo = UIImage(named: "browse_back")
var hexColor = 0x21BBD4 as UInt
self.navigationBar.barTintColor = GeneralHelper.UIColorFromRGB(hexColor)
self.navigationItem.titleView = UIImageView(image: logo)
}
}
Here is my code for setting the titleView to an image.
When I run the application, the color of the navigation bar is being changed to the correct color, but the titleView image is not displaying.
I've tested to ensure the image does exist.
Thanks.
The managing UINavigationController object uses the navigation items
of the topmost two view controllers to populate the navigation bar
with content.
Source: UINavigationItem Class Reference
You have to set the titleView of the navigationItem of the controller that is the top most controller in the navigation stack managed by your custom navigation controller.
For those using a UILabel as your titleView
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
navigationItem.titleView?.sizeToFit()
}
Hope this works!
How would I change the navigation bar color based on what page the user is on?
I would like to do something similar to what the Vine app uses in the explore category when the user taps a certain category and it turns into the color of the button in a fading format. Any thoughts on how to do this?
You can try to set the navigation bar tint color in the prepareForSegue: method (in your controller whit the four buttons) like this
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:"segueIdentifier here"]) {
[self.navigationController.navigationBar setBarTintColor:[UIColor redColor]];
}
}
Don't forget to reset the navigation bar tint color when you came back (do this in the viewWillAppear)
Or you can try to do this in all your controllers in the method viewWillAppear: like this
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self.navigationController.navigationBar setBarTintColor:[UIColor redColor]];
}
Solution for Swift 3.0 (tested on iOS 10)
Hi! I faced the same problem and finally I've found good solution.
Setting the navigation bar's color in viewWillAppear method works fine when you push from a parent to a child view. Transition between navigation bars colors is smooth.
class ChildViewController: UIViewController {
...
override func viewWillAppear(_ animated: Bool) {
self.navigationController?.navigationBar.barTintColor = UIColor.white
}
But it didn't really worked for setting the bar's color in the ParentViewController to the original one. You could notice the color's change, that looked just ugly and unprofessional.
To make the color change smooth when coming back to ParentViewController, do it within the method willMove(toParentViewController parent: UIViewController?) in your ChildViewController:
class ChildViewController: UIViewController {
...
override func willMove(toParentViewController parent: UIViewController?) {
self.navigationController?.navigationBar.barTintColor = UIColor.red
Thanks to this approach you can set different navigation bar colors on different pages in the one Navigation Controller with smooth colors transitions between view in both ways - going to a child view and also coming back to parent.
This is the swift version of how to change navigation bar color on different pages.
You can write this line of code in the viewDidLoad() method of any view controller in which you want to change the color of navigation bar.
self.navigationController!.navigationBar.barTintColor = UIColor.orangeColor()
and then you can use the method viewWillAppear() method so that when you come back to the same view controller from another different controller the color remains same
viewWillAppear(){
self.navigationController!.navigationBar.barTintColor = UIColor.orangeColor()
}
Swift 4+
super.viewDidLoad()
let newBackButton = UIBarButtonItem(title: "B",
style: UIBarButtonItem.Style.plain, target: self, action: "backAction")
navigationController?.navigationBar.topItem?.backBarButtonItem = newBackButton
newBackButton.tintColor = .red
// Do any additional setup after loading the view.
}
func backAction() -> Void {
self.navigationController?.popViewController(animated: true)
}