When I try to add a custom UINavigationBar to a view controller like this
class ViewController: UIViewController
{
static let nav_bar_height: CGFloat = 64
let nav_bar: UINavigationBar =
{
let nav_bar = UINavigationBar()
nav_bar.translatesAutoresizingMaskIntoConstraints = false
nav_bar.backgroundColor = .blue
return nav_bar
}()
override func viewDidLoad()
{
super.viewDidLoad()
view.backgroundColor = .yellow
view.addSubview(nav_bar)
nav_bar.heightAnchor.constraint(equalToConstant: ViewController.nav_bar_height).isActive = true
nav_bar.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
nav_bar.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
nav_bar.widthAnchor.constraint(equalToConstant: UIScreen.main.bounds.width).isActive = true
}
}
two distinct bars show up.
Any idea on why there is the white colored bar with a smaller height?
This is the AppDelegate
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
window?.makeKeyAndVisible()
let vc = ViewController()
window?.rootViewController = vc
// Override point for customization after application launch.
return true
}...
You're probably in navigation interface with a UINavigationController as your view controller's parent.
So the second navigation bar is the UINavigationController's navigation bar.
Related
I am trying to make a UITabBarController and a UINavigationController programmatically. I've tried many tutorials but most use Swift 3 which is too outdated and doesn't work.
AppDelegate.swift Snippet:
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
window = UIWindow(frame: UIScreen.main.bounds)
let journalVC = JournalTableViewController()
let navController = UINavigationController(rootViewController: journalVC)
window?.rootViewController = navController
window?.makeKeyAndVisible()
return true
}
JournalTableViewController.swift Snippet:
var tabBarCnt = UITabBarController()
override func viewDidLoad() {
super.viewDidLoad()
tabBarCnt = UITabBarController()
tabBarCnt.tabBar.barStyle = .black
let journalVC = JournalTableViewController()
journalVC.tabBarItem = UITabBarItem(tabBarSystemItem: .favorites, tag: 0)
tabBarCnt.viewControllers = [journalVC]
self.view.addSubview(tabBarCnt.view)
}
What works:
The build loads onto the simulator
What doesn't work:
The build crashes once loading onto the simulator
After crashing, the error Thread 1: EXC_BAD_ACCESS (code=2, address=0x7ffee6c2ada8) apears over this line 12 of JournalTableViewController.swift Snippet
If you are going to combine a UITabBarController and a UINavigationController then you will want the tab bar controller to be the root view controller. Each tab can have its own navigation controller if required.
If you make the navigation controller the root, then as soon as you push a new view controller, the tab bar will disappear. By making the tab bar the root, you can have a series of navigation hierarchies and switch quickly between them using the tab buttons.
AppDelegate.swift
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
window = UIWindow(frame: UIScreen.main.bounds)
let journalVC = JournalViewController()
let navController = UINavigationController(rootViewController: journalVC)
let tabBarController = UITabBarController()
navController.tabBarItem = UITabBarItem(tabBarSystemItem: .favorites, tag: 0)
tabBarController.viewControllers = [navController]
window?.rootViewController = tabBarController
window?.makeKeyAndVisible()
return true
}
There is no need for any specific code in your view controller class.
JournalTableViewController.swift Snippet:
override func viewDidLoad() {
super.viewDidLoad()
}
I think there is a typo in your snippet. In the following code, we added an intermediate vc to solve recursive problems.
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
window = UIWindow(frame: UIScreen.main.bounds)
let journalVC = JournalViewController()
let navController = UINavigationController(rootViewController: journalVC)
window?.rootViewController = navController
window?.makeKeyAndVisible()
return true
}
Here is journal vc:
class JournalViewController: UIViewController{
var tabBarCnt = UITabBarController()
override func viewDidLoad() {
super.viewDidLoad()
tabBarCnt = UITabBarController()
tabBarCnt.tabBar.barStyle = .black
let journalVC = JournalTableViewController()
journalVC.tabBarItem = UITabBarItem(tabBarSystemItem: .favorites, tag: 0)
tabBarCnt.viewControllers = [journalVC]
self.view.addSubview(tabBarCnt.view)
}
}
while the tableviewcontroller should be like this:
class JournalTableViewController: UITableViewController{
}
I'm trying to learn how to programmatically create the UI of my application.
I added to the application a navigation controller with code, this is the code:
AppDelegate:
var window: UIWindow?
var navigationController: UINavigationController?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
if let window = window{
let mainVC = MainVC()
navigationController = UINavigationController(rootViewController: mainVC)
window.rootViewController = navigationController
window.makeKeyAndVisible()
}
return true
}
And this is my mainVC:
class MainVC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.white
navigationController?.navigationBar.isTranslucent = false
navigationController?.navigationBar.barTintColor = UIColor.blue
navigationController?.navigationBar.prefersLargeTitles = true
navigationItem.title = "Hello"
setupTextBox()
// Do any additional setup after loading the view, typically from a nib.
}
let textBox: UITextField = {
var tBox = UITextField(frame: CGRect(x: 100, y: 100, width: 200, height: 30))
tBox.placeholder = "Please Enter Name"
tBox.textAlignment = .center
tBox.borderStyle = .roundedRect
tBox.backgroundColor = UIColor.red
return tBox
}()
private func setupTextBox(){
view.addSubview(textBox)
}
}
The navigation bar does appear but it is huge, couldn't find a way to view it as it should be.
This is the image of the navigation bar:
What am I doing wrong?
Its because of navigationController?.navigationBar.prefersLargeTitles = true
You are doing well
Just must to understand that it is iPhone X with top safe area + LARGE TITLE
You're not doing anything wrong. That's simply how a UINavigationBar looks on iPhone X, iPhone XR and iPhone XS. All of these devices have the "X" bevel.
Here's another helpful SO post: What is the top bar height of iPhone X?
The large navigation bar is a style of navigation bar that is used when prefersLargeTitles is set. So this line is causing your issue
navigationController?.navigationBar.prefersLargeTitles = true
Change that to false and you should get a smaller* navigation bar
Note: * it will still be larger than normal due to the 'notch' on the iPhone X range of devices
I am trying to implement bottom navigation bar for my iOS application. However, when I am creating tabBarItem, it is not showing on TabBar. TabBar is displaying correctly. I cannot figure out where is the problem, any help will be very appreciated.
If any additional information is required, please give me a sign. My code (simplified):
AppDelegate:
class AppDelegate: UIResponder, UIApplicationDelegate, GIDSignInDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
window?.makeKeyAndVisible()
window?.rootViewController = TabBarController()
return true
}
}
TabBarController:
class TabBarController: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
let homeController = HomeController()
let navigationController = UINavigationController(rootViewController: homeController)
navigationController.title = "Home"
navigationController.tabBarItem.image = UIImage(named: "icon")
viewControllers = [homeController]
}
}
HomeController:
class HomeController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.tabBarController?.tabBar.isHidden = false
}
}
EDIT:
I removed not crucial parts of the code, like isLoggedIn() function call, mentioned in the comments and changed MainNavigationController to TabBarController.
According to Matts answer I also changed this line in a TabBarController (but still bar item is not showing for some reason):
viewControllers = [navigationController]
The problem is this line:
viewControllers = [homeController]
homeController is not navigationController. So what happened to navigationController? Nothing. It vanished in a puff of smoke. You created navigationController but then you threw it away.
So nothing you say about navigationController and its configuration (including its tab bar item) has any effect; it is not in the interface (or anywhere else).
This is my complete test code (based on your code):
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
window?.makeKeyAndVisible()
window?.rootViewController = MainNavigationController()
return true
}
}
class MainNavigationController: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
let homeController = HomeController()
let navigationController = UINavigationController(rootViewController: homeController)
navigationController.tabBarItem.title = "MyCoolTitle"
viewControllers = [navigationController] // not [homeController]
}
}
class HomeController: UIViewController {
}
This question already has answers here:
UICollectionView: must be initialized with a non-nil layout parameter
(7 answers)
Closed 4 years ago.
I am new in Swift. I have 3 UIViewControllers:
MainScreenController
RegistrationFormController
LoginFormController
and 1 UITabBarController
MainTabBarController
and 2 ColletionViewControllers:
VideoController
TopVideoController
When I click on the button on the LoginFormController to open MainTabBarController with either 2 ColletionViewControllers seems an error, the error is mentioned below:
'UICollectionView must be initialized with a non-nil layout parameter'
AppDelegate:
class CustomNavigationController: UINavigationController {
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
}
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var navigationController: UINavigationController?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
if let window = window {
let mainVC = MainScreenController()
navigationController = CustomNavigationController(rootViewController: mainVC)
window.rootViewController = navigationController
window.makeKeyAndVisible()
}
UINavigationBar.appearance().isTranslucent = false
UINavigationBar.appearance().tintColor = .white
UINavigationBar.appearance().barTintColor = UIColor.darkBlue
UINavigationBar.appearance().titleTextAttributes = [NSAttributedStringKey.foregroundColor: UIColor.white]
UINavigationBar.appearance().largeTitleTextAttributes = [NSAttributedStringKey.foregroundColor: UIColor.white]
FirebaseApp.configure()
return true
}
Help me to understand how it works.
From the Apple Documentation, you need to use init(frame: CGRect,
collectionViewLayout layout: UICollectionViewLayout) when initializing your collection view controllers.
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
self.window?.backgroundColor = UIColor.whiteColor()
self.window?.makeKeyAndVisible()
let vc = ViewController()
vc.tabBarItem = UITabBarItem(...)
...
let tabbar = UITabBarController()
tabbar.setViewControllers([...,vc,...], animated: false)
self.window?.rootViewController = tabbar
tabbar.selectedIndex = 2
return true
}
}
class ViewController: UIViewController {
override func loadView() {
super.loadView()
self.view.backgroundColor = UIColor.yellowColor()
//self.automaticallyAdjustsScrollViewInsets = false;
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
}
}
I am not using a story board.
The above causes the ViewControllers view to extend below the tab bar. How can i stop this?
I've tried setting the views frame to
CGRectMake(0, 0, self.view.frame.width, self.view.frame.height - tabBarController.view.frame.height))
but that did not work.
You can use the edgesForExtendedLayout property of UIViewController to set which edges to extend under navigation bars. If you don't want any, you can simply say:
self.edgesForExtendedLayout = .None
For Swift 5 or above
self.edgesForExtendedLayout = []