I feel like I'm completely overlooking something, since this is so basic.
In a completely bare bones setup:
window = UIWindow(frame: UIScreen.mainScreen().bounds)
window.backgroundColor = UIColor.whiteColor()
let rootController = MainViewController()
rootNavigationController = UINavigationController(rootViewController: rootController)
window.rootViewController = rootNavigationController;
window.makeKeyAndVisible()
// Appearance
UINavigationBar.appearance().barTintColor = UIColor.DailyRate.blueColor
UINavigationBar.appearance().titleTextAttributes = [NSForegroundColorAttributeName: UIColor.whiteColor()]
UINavigationBar.appearance().opaque = false
I get a navigation bar that does not extend behind the status, which should be default behavior.
I just tried and I got proper result. Please find my complete code. I can not find few things in your code(I don't get what you mean by DailyRate) , remaining things are same as your code.
var window: UIWindow?
var rootNavigationController : UINavigationController?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
window = UIWindow(frame: UIScreen.mainScreen().bounds)
window!.backgroundColor = UIColor.whiteColor()
let rootController = ViewController()
rootNavigationController = UINavigationController(rootViewController: rootController)
window!.rootViewController = rootNavigationController;
window!.makeKeyAndVisible()
// Appearance
UINavigationBar.appearance().barTintColor = UIColor.blueColor()
UINavigationBar.appearance().titleTextAttributes = [NSForegroundColorAttributeName: UIColor.whiteColor()]
UINavigationBar.appearance().opaque = false
// Override point for customization after application launch.
return true
}
And the result is in following attachment.
I encountered this problem because I was removing the built-in line border at the bottom of the navigation bar, like this:
if let navigationBar = self.navigationController?.navigationBar {
navigationBar.shadowImage = UIImage()
navigationBar.setBackgroundImage(UIImage(), forBarMetrics: .Default)
navigationBar.backgroundColor = UIColor.redColor()
}
I was doing the above code inside my view controller's viewWillAppear because some of my VCs have other colors for the navigation bar and I don't want to modify the universal appearance.
The solution was to just create a 1 pt x 1 pt image with the color I want and use it instead of a new empty UIImage instance, like this:
if let navigationBar = self.navigationController?.navigationBar {
let colorImage = UIImage.imageWithColor(self.category.color)
navigationBar.shadowImage = colorImage
navigationBar.setBackgroundImage(colorImage, forBarMetrics: .Default)
navigationBar.tintColor = UIColor.whiteColor()
}
imageWithColor is a function I defined in an extension to UIImage:
class func imageWithColor(color: UIColor) -> UIImage {
let rect = CGRectMake(0, 0, 1, 1)
UIGraphicsBeginImageContext(rect.size)
let context = UIGraphicsGetCurrentContext()
CGContextSetFillColorWithColor(context, color.CGColor)
CGContextFillRect(context, rect)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
It turned out that it was a timing issue.
The root hierarchy was actually set up in the initializer of a separate class called UIManager. However, this class was initialized at the same time as the AppDelegate
var uiManager = UIManager()
and not in application(_, didFinishLaunchingWithOptions _) method, thus creating this weird scenario.
So all I did was
var uiManager: UIManager?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
uiManager = UIManager()
}
And now everything is back to normal.
Thanks to #govindarao-kondala for planting the right idea in my head!
Related
I have run into some issues running xcode 14 and ios 16.
The navigation bar does not change colors, and the Tab Bar is the same color as the background (I think it should have a different tint).
class MainTabController: UITabBarController {
// MARK: - Properties
// MARK: - Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
configureViewControllers()
}
// MARK: - Helpers
func configureViewControllers() {
let feed = FeedController()
let nav1 = templateNavigationController(image: UIImage(named: "home_unselected"), rootViewController: feed)
let explore = ExploreController()
let nav2 = templateNavigationController(image: UIImage(named: "search_unselected"), rootViewController: explore)
let notifications = NotificationsController()
let nav3 = templateNavigationController(image: UIImage(named: "search_unselected"), rootViewController: notifications)
let conversations = ConversationsController()
let nav4 = templateNavigationController(image: UIImage(named: "search_unselected"), rootViewController: conversations)
viewControllers = [nav1, nav2, nav3, nav4]
}
func templateNavigationController(image: UIImage?, rootViewController: UIViewController) -> UINavigationController {
let nav = UINavigationController(rootViewController: rootViewController)
nav.tabBarItem.image = image
nav.navigationBar.barTintColor = .white
return nav
}
}
I have tried setting the appearance of the navigation bar:
let appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground()
appearance.backgroundColor = .white
nav.navigationBar.standardAppearance = appearance
nav.navigationBar.scrollEdgeAppearance = nav.navigationBar.standardAppearance
this seems a bit redundant, and do you have to do this everytime for each nav controller?
No, you don't have to do this for each Navigation Controller.
You can make an extension of UINavigationBar.
extension UINavigationBar {
static func create() {
let navBarAppearance = UINavigationBarAppearance()
navBarAppearance.configureWithOpaqueBackground()
navBarAppearance.backgroundColor = .white
appearance().standardAppearance = navBarAppearance
appearance().scrollEdgeAppearance = navBarAppearance
appearance().compactAppearance = navBarAppearance
}
}
and call UINavigationBar.create() from your application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool
Similar approach can be done for the UITabBar
I am building an iOS app, deployment target 12.1, swift 4.2. The app uses container views and has a navigation bar at the top of the main screens, preferably right under the status bar. In the launchscreen storyboard, I have constrained Navigation Bar.top to Safe.Area.Top. That works fine. But after I set the containerViewController to be the rootViewController in the AppDelegate, the navigation bar as I've constrained it in Main.storyboard (Navigation Bar.top to Safe.Area.Top) appears far below where it should be.
The only way I can get the navigation bar to appear right under the status bar is to create a custom frame for my window in AppDelegate with a negative y-value -- and that is definitely NOT a solution I'm comfortable with.
This seems to generate a y-value too low:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
window = UIWindow(frame: UIScreen.main.bounds)
let containerViewController = ContainerViewController()
window!.rootViewController = containerViewController
window!.makeKeyAndVisible()
return true
}
And this is the egregious hack that gets the navigation bar closer to where it should be:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
//window = UIWindow(frame: UIScreen.main.bounds)
let hackedFrame = CGRect(x: 0, y: -44, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
window = UIWindow(frame: hackedFrame)
let containerViewController = ContainerViewController()
window!.rootViewController = containerViewController
window!.makeKeyAndVisible()
//window!.windowLevel = UIWindow.Level.statusBar
return true
}
Screen grabs:
I'm probably missing something really obvious here, but I'd appreciate any help anyone can give.
Thanks.
In iOS 11 Apple introduced large titles in the navigation bar, which means that it can be stretched if pulled. You should try setting
navigationItem.largeTitleDisplayMode = .never
In your viewDidLoad, and set the prefersLargeTitles of your navigation bar to false
if #available(iOS 11.0, *) {
navigationItem.largeTitleDisplayMode = .always
navigationController?.navigationBar.prefersLargeTitles = true
}
try adding the navigation bar in ViewController instead of AppDelegate like this:
var screenWidth : CGFloat!
var screenHeight : CGFloat!
let screenSize: CGRect = UIScreen.main.bounds
inside ViewDidLoad:
screenWidth = screenSize.width
screenHeight = screenSize.height
navigationBar = UINavigationBar(frame: CGRect(x: 0, y: 20, width: screenWidth, height: screenWidth / 3))
for adding title and button:
view.addSubview(navigationBar)
let navItem = UINavigationItem(title: "MainController")
let doneItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.cancel, target: nil, action: #selector(DismissViewController))
navItem.leftBarButtonItem = doneItem
UINavigationBar.appearance().barTintColor = .white
navigationBar.setItems([navItem], animated: false)
I'm writing my app router like this:
final class AppRouter {
let navigationController: UINavigationController
init(window: UIWindow) {
navigationController = UINavigationController()
window.rootViewController = navigationController
...
}
I'm calling router initialiser in application:didFinishLaunchingWithOptions: method.
I was trying to change it style (colour, font and other) by changing it properties, child properties, using UINavigationBar.appearance()
Nothing works. I was setting translucent to false. Only storyboard changes are making any effect, but then I have storyboard based navigation, that I don't want to have.
I have seen many posts about this issue, nothing is working.
If someone have cookbook, that is working on newest iOS (currently 11.4), please share!
Edit:
Like I said making changes like:
UINavigationBar.appearance().barTintColor = color
UINavigationBar.appearance().isTranslucent = false
this is used in didFinishLaunching.
or in constructor:
navigationController.navigationBar.barTintColor = color
Both methods fail to set color of navigation controller bar.
Edit 2:
App delegate calls:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let window = UIWindow(frame: UIScreen.main.bounds)
self.window = window
window.makeKeyAndVisible()
appRouter = AppRouter(window: window)
return true
}
Use below extension for UINavigationController
extension UINavigationController
{
func setMainTopNavigationBarAttribute() -> Void
{
self.navigationBar.shadowImage = UIImage()
self.navigationBar.isTranslucent = false
self.navigationBar.barTintColor = UIColor.black
self.navigationBar.tintColor = UIColor.white
self.navigationBar.backgroundColor = UIColor.clear
let navBarAttributesDictionary: [NSAttributedStringKey: Any]? = [
NSAttributedStringKey.foregroundColor: UIColor.black,
NSAttributedStringKey.font: UIFont(name: "HelveticaNeue-Bold", size: 18.0)
]
self.navigationBar.titleTextAttributes = navBarAttributesDictionary
}
}
final class AppRouter {
let navigationController: UINavigationController
init(window: UIWindow) {
navigationController = UINavigationController()
window.rootViewController = navigationController
navigationController.setMainTopNavigationBarAttribute()
}
I want to add logo on top left corner in Navigation Bar. I tried in design time but didn't worked for me.
Below is grab of screenshot that I want.
Here is code that I tried :
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
let imgLogo : UIImage = UIImage(named:"Logo")!
let imgViewLogo : UIImageView = UIImageView(image: imgLogo)
imgViewLogo.frame = CGRectMake(20, 2, 60, 60)
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
let objNavigationController = UINavigationController()
objNavigationController.navigationBar.addSubview(imgViewLogo)
let mainView = ViewController(nibName: nil, bundle: nil)
objNavigationController.viewControllers = [mainView]
self.window!.rootViewController = objNavigationController
self.window?.makeKeyAndVisible()
return true
}
Any help would be appreciated.
You have to put it inside an UIImageView
let logo = UIImage(named: "logo.png")
let imageView = UIImageView(image:logo)
self.navigationItem.titleView = imageView
I am trying to learn Swift and iOS Views and ViewControllers.
var window: UIWindow?
var rootViewController: MyCustomView?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
// Override point for customization after application launch.
self.rootViewController = MyCustomView()
self.rootViewController!.backgroundColor = UIColor.orangeColor()
var rect = CGRectMake(20, 20, 100, 100)
var label = UILabel(frame: rect)
label.text = "Hello iOS Views"
label.backgroundColor = UIColor.orangeColor()
self.window!.rootViewController = self.rootViewController
self.window!.backgroundColor = UIColor.whiteColor()
self.window!.makeKeyAndVisible()
return true
I am getting an error when I compile, "Could not find member 'rootViewController'" on the following line:
self.window!.rootViewController = self.rootViewController
Not sure why Xcode 6 Beta is not liking it but it's able to find this line:
self.rootViewController!.backgroundColor = UIColor.orangeColor()
The problem is that MyCustomView is a UIView. But UIWindow's rootViewController expects a UIViewController.
Generally you have confused yourself right through your code by not distinguishing view controllers from views. But you did name MyCustomView sensibly, which is good. The fact that it has a backgroundColor helps to prove that it is a view, not a view controller (view controllers have no background color).