In swift 3, I was able to change the height of a custom navigation bar using constraints and simply setting the height. Now I cannot do that anymore. It doesn't actually change the height of the navigation bar in the storyboard. Even when I go to the size inspector, the height field is gray and I am not able to change it. What is the best practice if I am presenting a view modally and want to display a navigation bar? It doesn't display automatically since it is a modally segue.
I had a similar issue, so i started to research and i found a solution that works for me... I'm gonna show how i did it, but i have to say that i don't use storyboards, so it is all in code...
1) You have to create a class of type "UIView", and then put this code in it:
class ExtendedNavBarView: UIView {
override func willMove(toWindow newWindow: UIWindow?) {
super.willMove(toWindow: newWindow)
layer.shadowOffset = CGSize(width: 0, height: CGFloat(1) / UIScreen.main.scale)
layer.shadowRadius = 0
layer.shadowColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1).cgColor
layer.shadowOpacity = 0.25
}
2) Then, go to the class where you have your navigationController. In the viewDidLoad method, put this code:
navBar.shadowImage = #imageLiteral(resourceName: "TransparentPixel")
let extendedBar = ExtendedNavBarView()
extendedBar.frame = CGRect(x: 0, y: 0, width: view.bounds.width, height: 82) //The height value is gonna determinate the total height of the navbar
view.addSubview(extendedBar)
extendedBar.backgroundColor = UIColor(red: 249/255, green: 249/255, blue: 249/255, alpha: 1.0)
Basically is an extension view for the navigationBar, depending of the value you put in the height, the total navbar is gonna be more or less taller.
If you want to learn more about it, you can go here:
Custom NavigationBar
Also, the "TransparentPixel" image is in the page, you just have to download the sample project.
Related
I have decided to learn to use Swift without storyboards. Before making the switch, I had a function in a file called Utilities.swift that has a function to style the text fields, which worked fine when I had a storyboard.
class Utilities {
static func styleTextField(_ textfield:UITextField) {
let bottomLine = CALayer()
bottomLine.frame = CGRect(x: 0, y: textfield.frame.height - 2, width: textfield.frame.width, height: 2)
bottomLine.backgroundColor = UIColor.init(red: 48/255, green: 173/255, blue: 99/255, alpha: 1).cgColor
textfield.borderStyle = .none
textfield.layer.addSublayer(bottomLine)
}
}
Then in my view controller, I have let firstName = UITextField() and then a function for Utilities.styleTextField(firstName), which when I had storyboards, worked fine. After removing storyboards and adding constraints programmatically, I can see the text field but it is default without styling.
My guess is that, at this point, you didn't set the text field's frame yet, so the CALayer is not being drawn because its size is (width: 0, height: 0).
When you get the component from IB, it comes with a frame, which is the one you set in the tool.
Try setting the frame before calling the function.
I am populating the collection view cells. But only for a single cell, I want a different background color with shadow to the cell. So far I am able to give background color but can't find any idea, how to give shadow. Any suggestions...
cell.backgroundColor = UIColor.init(alpha: 1, red: 255, green: 221, blue: 126)
let view = UIView()
view.frame = CGRect(x: 20, y: cell.frame.origin.y + 62, width: cell.frame.size.width, height: 50)
view.layer.shadowColor = UIColor.black.cgColor
view.layer.shadowOffset = CGSize(width: 3, height: 3)
view.layer.shadowOpacity = 0.9
view.backgroundColor = UIColor.clear
self.addSubview(view)
return cell
This is what I did
This is what I want
I can give you a way of doing it.
Give your cell a clear color
Add a child view in it make sure to give proper constrains (make sure to keep the child view inside the cell).
Add all labels or any other views inside the new child view
Give shadows and background color to the child view.
(make sure to toggle the color when needed just as selected color)
I am sure this will definitely look the image you have sown
I upgraded to a new iphone and upgrade my apps. I added in the x/xr/xs layout so the black borders are gone now.
I have a navigation bar at the top of my views but now it rides up into the status bar too much? How do I fix this? Doing it programmatically and not storyboard (to learn code).
Some code:
func buildTopbar()
{
statusbar = UIView(frame: CGRect(x: 0, y: 0, width: self.view.bounds.width, height: 20));
statusbar.backgroundColor = UIColor(red: 247/255, green: 247/255, blue: 247/255, alpha: 1.0);
navigationbar = UINavigationBar(frame: CGRect(x: 0, y: 20, width: self.view.bounds.width, height: 44));
navigationbar.barTintColor = UIColor(red: 247/255, green: 247/255, blue: 247/255, alpha: 1.0);
let texta = UIBarButtonItem(title: "A", style: .plain, target: self, action: #selector(settingToolbar(sender:)));
let textb = UIBarButtonItem(title: "B", style: .plain, target: self, action: #selector(inviteToolbar(sender:)));
texta.tintColor = ColorHelper.primaryColor();
textb.tintColor = ColorHelper.primaryColor();
...
navigationbar.setItems([title], animated: false);
self.view.addSubview(statusbar);
self.view.addSubview(navigationbar);
}
I set the status bar at 20 which was what it was in the old phones.
I'd recommend to create a UINavigationController and add your controller to that Navigation Controller, it will automatically adjust the navigation bar.
In case you want to manually add the navigation bar.
You must set it's frame Y position right.
To calculate starting Y position of Nav bar
let startingYPos = UIApplication.sharedApplication.statusBarFrame.size.height;
navigationbar = UINavigationBar(frame: CGRect(x: 0, y: startingYPos, width: self.view.bounds.width, height: 44));
My suggestion is go with adding some constraints for the top.And set the constraints values based on your iPhone device size or iOS Versions. Recently i achieved it by setting like this. My issues was with iOS Version, my view is near to status bar.So i set some constraints programatically and handled it. This way it wont affect the iphone screens below iphone 7.
In Viewdidload()
if #available(iOS 11, *) {
}
else{
topConstraints.constant = 20
}
Here i checked the version's. You can also check the device and you can set the constraints. If you want for the device check, let me know.
Hope it will work !!
Height of status bar has changed now from 20pt to 44pt (from iPhone X onwards). If you want to use your existing code, you need to apply device specific check for status bar height.
Here is a post which explains nav bar layout(for iPhone X and later devices) in more detail:
What is the top bar height of iPhone X?
I would suggest you to take UIScreen height & put it in a condition:
if UIScreen.main.bounds.size.height > 750 {
navigationBar = UINavigationBar(frame: CGRect(x: 0, y: 43, width: view.frame.size.width, height: 44))
}
else{
navigationBar = UINavigationBar(frame: CGRect(x: 0, y: 20, width: view.frame.size.width, height: 44))
}
it may not work if your view's having a scrolling view & it's height is set to more than default value, then try :-
view.bounds.size.height
You can have it aligned to the safe area even without UINavigationController or some "magic" fixed height constants.
You should have #IBOutlet of your navigation bar (or reference if navigation bar is made programmatically). Also, keep the bar's top constraint to Safe area.
Make your ViewController conform to UINavigationBarDelegate and set delegate of navigation bar (navigationBar.delegate = self)
Implement this function and return .topAttached:
func position(for bar: UIBarPositioning) -> UIBarPosition { return .topAttached }
I would simply like to know how to make my navigation bar look like the one on the left in the image below:
My app uses a navigation controller, and the navigation bar by default looks like the screen on the right in the image. I don't like it being so small and would like it higher and also to be able to change the colour and the font of the text used for the header.
I would appreciate any help in how to do this and where to place the code.
thanks
There are many ways to costumize your navigation bar:
//You can change the bar style
navigationController?.navigationBar.barStyle = UIBarStyle.Black
// You can change the background color
navigationController?.navigationBar.barTintColor = UIColor(red: 4 / 255, green: 47 / 255, blue: 66 / 255, alpha: 1)
// You can add a logo on it
let navBarImageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 30, height: 30))
navBarImageView.contentMode = .ScaleAspectFit
let navBarImage = UIImage(named: "myNavBarLogo.png")
navBarImageView.image = navBarImage
navigationItem.titleView = navBarImageView
//You can change the text color
navigationController?.navigationBar.tintColor = UIColor.yellowColor()
//You can change the font
if let font = UIFont(name: "AppleSDGothicNeo-Thin", size: 34) {
UINavigationBar.appearance().titleTextAttributes = [NSFontAttributeName: font]
}
You just need to play with those attributs to get the Navigation Bar as you want.
I hope that helps you!
You can change the navigation bar in Interface Builder.
You can change the background color by changing the bar tint. You can also change the title font, color, and etc., as you can see below:
I am trying to fill the status bar background color to orange using the following
UINavigationBar.appearance().tintColor = UIColor.orangeColor()
UINavigationBar.appearance().barTintColor = UIColor.orangeColor()
UINavigationBar.appearance().titleTextAttributes = [NSForegroundColorAttributeName: UIColor.whiteColor()]
UIApplication.sharedApplication().setStatusBarStyle(UIStatusBarStyle.LightContent, animated: true)
However, I get a white status bar that should be filled with orange instead from following this example: Customize navigation bar appearance with swift
I am setting this up in the AppDelegate.swift file under didFinishLaunchingWithOptions method to apply it to the entire app.
I have edited my info.plist to the following: View controller-based status bar appearance => NO
Does anyone know what I am doing wrong?
Edit: I'm not sure if it matters but the view is in a UITabBarController
Edit 2: This is happening in all the views actually, not just the UITabBarController.
Edit 3: Thanks #Utsav Parikh
I am adding a view now on top of the status bar and it for a brief moment while the app loads the status bar is orange but, once it finishes loading it gets pushed OFF the view and replaced with the generic white status bar.
Why would this be happening?
let view = UIView(frame: CGRect(x: 0.0, y: 0.0, width: UIScreen.mainScreen().bounds.size.width, height: 20.0))
view.backgroundColor=UIColor.orangeColor()
self.window!.rootViewController!.view.addSubview(view)
Edit for Swift 3:
with UITabBarController
let view = UIView(frame: CGRect(x: 0.0, y: 0.0, width: UIScreen.main.bounds.size.width, height: 20.0))
view.backgroundColor = .orange
self.view.addSubview(view)
Without embedded controllers
I realize some people come here not only for the status bar, but actually the navigation bar, so I learned a few tricks along the way to do it without any embedded controllers:
Add this method in your AppDelegate.swift and call it in the didFinishLaunchingWithOptions
func customizeAppearance() {
UINavigationBar.appearance().barTintColor = UIColor.black
UINavigationBar.appearance().titleTextAttributes = [NSForegroundColorAttributeName: UIColor.white]
UITabBar.appearance().barTintColor = UIColor.black
let tintColor = UIColor(red: 255/255.0, green: 255/255.0, blue: 255/255.0, alpha: 1.0)
UITabBar.appearance().tintColor = tintColor
}
Edit for Swift 3:
With UITabBarController
let view = UIView(frame: CGRect(x: 0.0, y: 0.0, width: UIScreen.main.bounds.size.width, height: 20.0))
view.backgroundColor = .orange
self.view.addSubview(view)
Without embedded controllers
I realize some people come here not only for the status bar, but actually the navigation bar, so I learned a few tricks along the way to do it without any embedded controllers:
Add this method in your AppDelegate.swift and call it in the didFinishLaunchingWithOptions
func customizeAppearance() {
UINavigationBar.appearance().barTintColor = UIColor.black
UINavigationBar.appearance().titleTextAttributes = [NSForegroundColorAttributeName: UIColor.white]
UITabBar.appearance().barTintColor = UIColor.black
let tintColor = UIColor(red: 255/255.0, green: 255/255.0, blue: 255/255.0, alpha: 1.0)
UITabBar.appearance().tintColor = tintColor
}
Thanks to #Utsav I added the following subview to my UITabBarController and this seems to be working now:
let view = UIView(frame:
CGRect(x: 0.0, y: 0.0, width: UIScreen.mainScreen().bounds.size.width, height: 20.0)
)
view.backgroundColor = UIColor.orangeColor()
self.view.addSubview(view)
The UITabBarController doesn't seem to play well in AppDelegate. If anyone has a better way let me know but, as of now this is the solution I have come around to.
Add this code in didFinishLaunchingWithOptions in AppDelegate
let view = UIView(frame: CGRect(x: 0.0, y: 0.0, width: UIScreen.mainScreen().bounds.size.width, height: 20.0))
view.backgroundColor=UIColor.orangeColor()
self.window.rootViewController.view.addSubview(view)
Hope it helps you....!!!
This is how I did it without adding a view in a VC with in a NavBarController
I wanted the color of the status bar to be the same as the VC view color so I just wrote:
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.grayColor()
self.navigationController?.navigationBar.clipsToBounds = true
}
Try it.
I think your last line is reverting your changes, try this:
override func viewWillAppear(animated: Bool) {
UIApplication.sharedApplication().setStatusBarStyle(UIStatusBarStyle.LightContent, animated: true)
super.viewWillAppear(animated)
var nav = self.navigationController?.navigationBar
nav?.barStyle = UIBarStyle.Black
nav?.tintColor = UIColor.orangeColor()
nav?.titleTextAttributes = [NSForegroundColorAttributeName: UIColor.whiteColor()]
}
After what u did in info.plist to the following: View controller-based status bar appearance => NO.
Add this code in AppDelegate.swift file under didFinishLaunchingWithOptions:
var navigationBarAppearace = UINavigationBar.appearance()
navigationBarAppearace.tintColor = uicolorFromHex(0xffffff)
navigationBarAppearace.barTintColor = uicolorFromHex(0x2E9AFE)
// change navigation item title color
navigationBarAppearace.titleTextAttributes = [NSForegroundColorAttributeName:UIColor.whiteColor()]
UIApplication.sharedApplication().statusBarStyle = UIStatusBarStyle.LightContent
and u can select any hex code for ur choice of color..!! Enjoy..!!
Sorry, forgot to use hexcode you will be needing this also so add this code anywhere in your AppDelegate.swift:
func uicolorFromHex(rgbValue:UInt32)->UIColor {
let red = CGFloat((rgbValue & 0xFF0000) >> 16)/256.0
let green = CGFloat((rgbValue & 0xFF00) >> 8)/256.0
let blue = CGFloat(rgbValue & 0xFF)/256.0
return UIColor(red:red, green:green, blue:blue, alpha:1.0)
}
Simon's answer in swift 3
let view = UIView(frame: CGRect(x: 0.0, y: 0.0, width: UIScreen.main.bounds.size.width, height: 20.0))
view.backgroundColor = .orange
self.view.addSubview(view)
There is one other way I know which uses private api. This has some benefits when orientation changes and keyboard is presented and view move up. I've used it and was lucky every time (app was released in the app store).
func setStatusBarBackgroundColor(color: UIColor) {
guard let statusBar = UIApplication.shared.value(forKeyPath: "statusBarWindow.statusBar") as? UIView else { return }
statusBar.backgroundColor = color
}
Swift 3:
In your AppDelegate.swift file paste the code bellow into your didFinishLaunchingWithOptions method:
let view = UIView(frame: CGRect(x: 0.0, y: 0.0, width: UIScreen.main.bounds.size.width, height: 20.0))
view.backgroundColor = UIColor(red: 255/255, green: 130/255, blue: 0/255, alpha: 1.0) // Organge colour in RGB
self.window?.rootViewController?.view.addSubview(view)
This works fine for me!
There is a main difference in tintColor and changing the background color of UINavigationBar. The best way in my opinion is apply a background image, made by 1 pixel square image of just one color.
Like that:
let tabbarAndNavBarBkg = UIImage(named: "nav_tab")
UINavigationBar.appearance().setBackgroundImage(tabbarAndNavBarBkg, forBarMetrics: .Default)
Or you can create a category on UIColor to return a UIImage given a UIColor instance, in objC:
+ (UIImage *) imageWithColor:(UIColor*) color {
CGRect rect = CGRectMake(0, 0, 1, 1);
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, color.CGColor);
CGContextFillRect(context, rect);
UIImage *colorImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return colorImage;
}
UINavigationBar.appereance() works for upcoming viewControllers, but not the currently displayed rootViewController. To achieve this I have added the following to my didFinishLaunchingWithOptions:
UINavigationBar.appearance().tintColor = myColor
let navigationController = UIApplication.sharedApplication().windows[0].rootViewController as! UINavigationController
navigationController.navigationBar.barTintColor = myColor
navigationController.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName : myTextColor]
navigationController.navigationBar.translucent = false
navigationController.setNeedsStatusBarAppearanceUpdate()