I am having a problem with my navigation Bars overlapping the Information on the top of the iPhone. I originally had the navigation bar as White/ Translucent and it didn't cause a problem. I feel that making it black would be better except for now it overlaps the Time, Battery and Data from the iPhone. How would I move the navigation bar down?
You need to create a custom navigationBar and then add the constraints that you want, but this is not something that should interrupt with the status bar usually. You could try to change the font size of your navigationBar text:
self.navigationController?.navigationBar.titleTextAttributes = [ NSAttributedStringKey.font: UIFont.systemFont(ofSize: 10)]
Update:
After some clarification, you donĀ“t want to move done the navigationBar, you just want to change the color of the statusBar (which contains all system icons on the top). Add these two rows in your viewDidLoad function to change the background color of you:
if let statusBar: UIView = UIApplication.shared.value(forKey: "statusBar") as? UIView {
statusBar.backgroundColor = .white
}
Just make this class parent class of your every viewController
For example you have a SignUpViewController class and currently your this view controller will be like this.
class SignUpViewController: UIViewController {
//Your all methods and properties are implemented here.
}
So just change the parent class of above class from UIViewController to below written class LargerNavigationBaseVC like this.
class SignUpViewController: LargerNavigationBaseVC {
//Your all methods and properties are implemented here.
}
class LargerNavigationBaseVC: UIViewController {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.navigationItem.prompt = " "
}
}
Related
Typically, translucent UINavigationBars have a light gray color above a white background.
However, many navigation bars throughout iOS 11 have a white color.
For example, navigation bars in the Files app are white AND translucent which are noticeably different from setting barTintColor to white.
How do I achieve this kind of effect on a UINavigationBar?
Set the barTintColor of the navigation bar to white.
After that, subclass UINavigationBar and set the shadow image to an empty UIImage.
class CustomNavBar: UINavigationBar {
override func awakeFromNib() {
super.awakeFromNib()
shadowImage = UIImage()
}
}
Finally, set the class of the navigation bar to the custom navigation bar class you just created.
Result
I was trying to build an app with the same style as the Files app, but ended up with the same problem.
It seems that when barTintColor is non-nil, UINavigationBar will disable the translucency effect, and there doesn't seem to be a public way to force it back on.
I think there is a reasonable way to get this effect though: you could replace the background view of the navigation bar with your own UIVisualEffectView.
It's possible to suppress both the background view, and the separator view of a navigation bar by providing them with dummy UIImage objects.
navigationBar.setBackgroundImage(UIImage(), for: .default)
navigationBar.shadowImage = UIImage()
You would need to create your own UINavigationBar subclass, suppress these two views, and then add your own UIVisualEffectView subview and position it to always sit at the bottom of the view stack.
It's not an amazing solution, but it should hopefully create the desired effect with minimal internal hacking of the navigation bar class.
So I've spent a huge amount of time researching this, and I've found the answer, but beware: it's very, very hacky.
So, the view that's responsible for creating this gray glow on the navigation bar is something called _UIVisualEffectBackdropView. More specifically, this view's layer has four filters attached (all of them are private CAFilters), and first of them, named luminanceCurveMap, creates this gray color for the navigation bar. So my solution is to
Find _UIVisualEffectBackdropView in the view hierarchy of UINavigationBar
Remove luminanceCurveMap filter of of its layer.
Here's the function I created to find _UIVisualEffectBackdropView in the hierarchy:
extension UIView {
fileprivate static func findRecursively(typeName: String, in view: UIView) -> UIView? {
let typeOf = type(of: view)
if String(describing: typeOf) == typeName {
return view
} else {
for subview in view.subviews {
if let found = UIView.findRecursively(typeName: typeName, in: subview) {
return found
}
}
return nil
}
}
}
And then override viewDidAppear in your custom UINavigationController subclass (only viewDidAppear, viewWillAppear for example didn't work):
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if let backdrop = UIView.findRecursively(typeName: "_UIVisualEffectBackdropView", in: navigationBar) {
let luminanceCurveMapIndex = backdrop.layer.filters?.firstIndex { filter in
if let caFilter = filter as? NSObject, let name = caFilter.value(forKey: "name") as? String {
return name == "luminanceCurveMap"
} else {
return false
}
}
if let index = luminanceCurveMapIndex {
backdrop.layer.filters?.remove(at: index)
}
}
}
I know it's a lot, but that's the I came out with. It preserves all native translucency behavior while giving me the look I needed.
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)
I'd like to create a subclass of the UINavigationController, so that I can set a specific style throughout my app - for example, a white font and a blue background.
I'm using swift, so I wrote this code:
import Foundation
import UIKit
class NavigationController : UINavigationController {
override func viewDidLoad(){
super.viewDidLoad()
self.navigationBar.backgroundColor = UIColor.blueColor()
self.navigationBar.translucent = false
}
}
I then changed the class of my navigation controller in the storyboard to this class - however this didn't work. It just did nothing, however when I remove the translucent = false line, I get a vaguely blue looking navigationBar.
What am I doing wrong? All the references on here I can find don't do it in this way or don't use swift.
Thanks!
i guess what you want to do is this:
self.navigationBar.barTintColor = UIColor.blueColor()
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!
I can create a UINavigationController with custom bar classes by using initWithNavigationBarClass:toolbarClass:. There doesn't seem to be an equivalent for UITabBarController, so how do I get it to use a custom UITabBar class?
Every solution I've seen so far is unsuitable because either
It uses IB
It adds a second tab bar to the UITabBarController instead of changing its existing one, or
It throws UITabBarController away and makes a new controller class.
I want a real UITabBarController created in code using a custom class for its tab bar. How do I achieve this?
This is surprisingly hard! The best I've come up with is subclassing UITabBarController and then doing this in the init:
super.init(nibName: nil, bundle: nil)
object_setClass(self.tabBar, CustomTabBar.self)
(self.tabBar as? CustomTabBar)?.setup()
Unfortunately you can't set the class before the call to super.init (not in Swift anyway), and so by the time you change the class the init method has already been run and so won't be called on your custom subclass. To get around this, I've just added a setup() method to do all my customisation in.
Another option in Swift is to extend UITabBar and do something like this:
extension UITabBar {
open override func willMove(toSuperview newSuperview: UIView?) {
super.willMove(toSuperview: newSuperview)
/// Customise in here.
}
// Modify the height.
open override func sizeThatFits(_ size: CGSize) -> CGSize {
return CGSize(width: size.width, height: 64.0)
}
}
However this will affect all instances of UITabBar, so I prefer the first option.
This solution from ESTabBarControlller, for replace native UITabBar without IB.
open override func viewDidLoad() {
super.viewDidLoad()
let tabBar = { () -> CustomTabBar in
let tabBar = CustomTabBar()
tabBar.delegate = self
return tabBar
}()
self.setValue(tabBar, forKey: "tabBar")
}
As far as I know you can't do this. Your best option to do this without IB is to have your own UIViewController (not subclassing UITabBarController) and then add your own subclass of UITabBar to that Controller.
You may also want to review the Controller Hierarchy if you decide to follow this approach.
I do not think it is possible.
Here is the Apple Documentation that talks about the tabBar property of UITabBarController.
You should never attempt to manipulate the UITabBar object itself
stored in this property. If you attempt to do so, the tab bar view
throws an exception. To configure the items for your tab bar
interface, you should instead assign one or more custom view
controllers to the viewControllers property. The tab bar collects the
needed tab bar items from the view controllers you specify.
The tab bar view provided by this property is only for situations
where you want to display an action sheet using the showFromTabBar:
method of the UIActionSheet class.