I'm developing an app that uses both a Tab Bar and a Nav Bar. Right now, both of these display on the first page that loads for the app, but only the Tab Bar displays when I navigate to different tabs.
My issue is that I'm not entirely sure where the Nav Bar is actually being told to display. I saw posts about having to tie your nav bar and tab bar together, but I didn't fully understand them, and trying to implement them caused my app to not load at all. Should I be instantiating the Nav Bar in each view controller?
This is my AppDelegate:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Initialize the window
window = UIWindow.init(frame: UIScreen.mainScreen().bounds)
// Set Background Color of window
window?.backgroundColor = UIColor.whiteColor()
// Make the window visible
window!.makeKeyAndVisible()
// Create TabBarController
let tabBarController = CustomTabBarController()
window?.rootViewController = tabBarController
return true
}
This is my CustomTabBarController.swift:
override func viewWillAppear(animated: Bool) {
// color TabBar correctly
let darkTeal = UIColor(red:0.09, green:0.62, blue:0.56, alpha:1.0)
let lightTeal = UIColor(red:0.6, green:0.78, blue:0.74, alpha:1.0)
UITabBar.appearance().barTintColor = darkTeal
UITabBar.appearance().tintColor = UIColor.whiteColor()
UITabBarItem.appearance().setTitleTextAttributes([NSForegroundColorAttributeName: UIColor.whiteColor()], forState:.Normal)
// customize TabBarItem width
let tabBarItemWidth = UIScreen.mainScreen().bounds.width / CGFloat(4)
UITabBar.appearance().selectionIndicatorImage =
UIImage().makeImageWithColorAndSize(lightTeal, size: CGSize(width: tabBarItemWidth, height: 49.0))
// create Tab Bar items
let findOutVC = FindOut()
let goOutVC = GoOut()
let speakOutVC = SpeakOut()
let reachOutVC = ReachOut()
// images
let findout = UIImage(named: "find_out")
let goout = UIImage(named: "go_out")
let speakout = UIImage(named: "speak_out")
let reachout = UIImage(named: "reach_out")
// modify tabBar items
findOutVC.tabBarItem = UITabBarItem(
title: "Find Out",
image: findout,
tag: 1)
goOutVC.tabBarItem = UITabBarItem(
title: "Go Out",
image: goout,
tag: 2)
speakOutVC.tabBarItem = UITabBarItem(
title: "Speak Out",
image: speakout,
tag: 3)
reachOutVC.tabBarItem = UITabBarItem(
title: "Reach Out",
image: reachout,
tag: 4)
// set up tabBar items
let tabs = [findOutVC, goOutVC, speakOutVC, reachOutVC]
self.viewControllers = tabs
}
And this is my CustomNavBarController.
override func viewDidAppear(animated: Bool) {
// Do any additional setup after loading the view.
let navigationBar = UINavigationBar(frame: CGRectMake(0, 20, self.view.frame.size.width, 44))
// change color of nav bar
let lightTeal = UIColor(red:0.6, green:0.78, blue:0.74, alpha:1.0)
navigationBar.barTintColor = lightTeal
navigationBar.translucent = true
navigationBar.delegate = self
let navigationItem = UINavigationItem()
navigationItem.title = "shOUT"
// left button
let leftButton = UIBarButtonItem(title: "Info", style: UIBarButtonItemStyle.Done, target: self, action: "openInfo")
let info = UIImage(named: "info")
leftButton.image = info
navigationItem.leftBarButtonItem = leftButton
// right button
let rightButton = UIBarButtonItem(title: "Pencil", style: UIBarButtonItemStyle.Done, target: self, action: "openWrite")
let pencil = UIImage(named: "pencil")
rightButton.image = pencil
navigationItem.rightBarButtonItem = rightButton
navigationBar.barStyle = UIBarStyle.Black
navigationBar.items = [navigationItem]
self.view.addSubview(navigationBar)
}
I suggest you to embed a NavigationController inside the TabBarController. Specifically, you should insert one NavigationController for each tab that you have in your TabBarController.
In this way your NavigationBar will always be visible during your navigation inside the tabs and the TabBar as well.
Here is an image of how your storyboard should look like:
Cheers!
Related
I'm trying to add some padding to the top of my tab bar but I can't find a clear answer on how to do so. I'm coming from a SwiftUI background and still trying to get the hang of UIKit.
Below is my code and a screenshot of my current tab bar.
class MainTabBarViewController: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .secondaryLabel
let home = UINavigationController(rootViewController: CoinListViewController())
let nilView1 = UINavigationController(rootViewController: CoinListViewController())
let nilView2 = UINavigationController(rootViewController: CoinListViewController())
let nilView3 = UINavigationController(rootViewController: CoinListViewController())
home.tabBarItem.image = UIImage(systemName: "house.fill")
nilView1.tabBarItem.image = UIImage(systemName: "magnifyingglass")
nilView2.tabBarItem.image = UIImage(systemName: "bitcoinsign.circle.fill")
nilView3.tabBarItem.image = UIImage(systemName: "person.fill")
home.title = "Home"
nilView1.title = "Search"
nilView2.title = "Coins"
nilView3.title = "Account"
tabBar.tintColor = .label
setViewControllers([home, nilView1, nilView2, nilView3], animated: true)
}
}
For some reason, I have to add a UINavagationController() inside a UIViewController(), so I did the following in the view controller class:
class someViewController: UIViewController {
private let myNav = UINavigationController()
override func viewDidLoad() {
self.addChildViewController(myNav)
self.view.addSubview(myNav.view)
myNav.view.translatesAutoresizingMaskIntoConstraints = false
myNav.view.topAnchor.constraintEqualToAnchor(self.topLayoutGuide.bottomAnchor).active = true
myNav.view.leftAnchor.constraintEqualToAnchor(view.leftAnchor).active = true
myNav.view.rightAnchor.constraintEqualToAnchor(view.rightAnchor).active = true
myNav.view.heightAnchor.constraintEqualToAnchor(nil, constant: 44).active = true
myNav.didMoveToParentViewController(self)
}
}
The navigation controller is added & showing up correctly. Then I try to add a title (or Done button) to the navigation bar, however the items just don't show up. I tried a few things like this:
self.navigationItem.title = "some title"
myNav.navigationItem.title = "some title"
myNav.navigationItem.rightBarButtonItem = btnDone
What's the right way to do it in this case?
Why don't you use this simple code to add a navigation bar :
let navigationBar = UINavigationBar(frame: CGRectMake(0, 0, self.view.frame.size.width, 66)) // Offset by 20 pixels vertically to take the status bar into account
// Create a navigation item with a title
let navigationItem = UINavigationItem()
navigationItem.title = "Title"
// Create left and right button for navigation item
let leftButton = UIBarButtonItem(title: "Save", style: UIBarButtonItemStyle.Plain, target: self, action: "btn_clicked:")
let rightButton = UIBarButtonItem(title: "Right", style: UIBarButtonItemStyle.Plain, target: self, action: nil)
// Create two buttons for the navigation item
navigationItem.leftBarButtonItem = leftButton
navigationItem.rightBarButtonItem = rightButton
// Assign the navigation item to the navigation bar
navigationBar.items = [navigationItem]
// Make the navigation bar a subview of the current view controller
self.view.addSubview(navigationBar)
I have this app, which has profile page. I have mainview in storyboard, tableview, and profile view.
When I go to profile view I want to be able to go back to mainview so I try something like this
class ProfileViewController: UIViewController, UITextFieldDelegate, UINavigationBarDelegate{
var bar: UINavigationBar!
override func viewDidLoad(){
super.viewDidLoad()
self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
bar = createBar();
}
func createBar() -> UINavigationBar{
let bar = UINavigationBar(frame: CGRectMake(0,0,self.view.frame.size.width,60))
bar.barTintColor = UIColor(red: 26/255, green: 53/255, blue: 72/255, alpha: 1.0)
bar.delegate = self
let navigationItem = UINavigationItem()
navigationItem.title = "Profile"
let leftButton = UIBarButtonItem(title: "Back", style: UIBarButtonItemStyle.Plain, target: self, action: "goBack:")
let rightButton = UIBarButtonItem(title: "Edit", style: UIBarButtonItemStyle.Plain,target: self, action: nil)
leftButton.tintColor = UIColor.whiteColor()
rightButton.tintColor = UIColor.whiteColor()
//bar.tittleTextAttributes = [UITextAttributeTextColor: UIColor.whiteColor()]
navigationItem.leftBarButtonItem = leftButton
navigationItem.rightBarButtonItem = rightButton
bar.items = [navigationItem]
self.view.addSubview(bar)
return bar;
}
func goBack(sender: UIBarButtonItem!){
if let navController = self.navigationController{
navController.popViewControllerAnimated(true)
}
}
}
I'm using SWRevealViewController.
Embed your Reveal View Controller in the UINavigationController.
Right now, the BackTable View Controller and the ProfileView Controller are not in Navigation Controller's hierarchy. Also, your segues should be push segues for this to work. Don't use modal segues.
Follow this simple tutorial for more clarity: http://code.tutsplus.com/tutorials/ios-from-scratch-with-swift-navigation-controllers-and-view-controller-hierarchies--cms-25462
First Embed RevealViewController in the UINavigation
navigationController!.popToViewController(navigationController!.viewControllers[0], animated: false)
On my main navigationController, there is a right bar button called "Next Page". When the button is pressed, it calls the method called "nextPage()" which initializes the navigation controller and show it.
The code for nextPage() is like following:
func nextPage() {
let window = UIWindow(frame: UIScreen.mainScreen().bounds)
let CustomLoginVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("viewControllerID") as! customVC
let navVC = UINavigationController.init(rootViewController: CustomLoginVC)
navVC.view.autoresizingMask = [.FlexibleHeight, .FlexibleWidth, .FlexibleTopMargin, .FlexibleLeftMargin]
navVC.navigationBar.translucent = false
navVC.navigationItem.title = "haha"
navVC.navigationBar.tintColor = UIColor.whiteColor()
navVC.navigationBar.titleTextAttributes = [NSFontAttributeName: UIFont(name: "AvenirNext-Medium", size: 22)!, NSForegroundColorAttributeName: UIColor.whiteColor() ]
navVC.navigationItem.leftBarButtonItem?.setTitleTextAttributes([NSFontAttributeName: UIFont(name: "AvenirNext", size: 18)!], forState: UIControlState.Normal)
let backButton = UIBarButtonItem.init(title: "Back", style: UIBarButtonItemStyle.Plain, target: self, action: "backButtonPressedInPDF")
let exportButton = UIBarButtonItem.init(image: UIImage(named: "export"), style: UIBarButtonItemStyle.Plain, target: self, action: "saveAsPDF")
navVC.navigationItem.setLeftBarButtonItem(backButton, animated: false)
navVC.navigationItem.setRightBarButtonItem(exportButton, animated: false)
window.rootViewController = navVC
self.presentViewController(navVC, animated: true, completion: nil)
}
As you can see I'm instantiating CustomLoginVC which is a type of customVC from Main storyboard. customVC is a subclass of UIViewController. Then, initialize UINavigationController with CustomLoginVC and assign left and right bar button items. However, title and bar button items are not shown on the nav bar like below image.
I'm not understanding why bar button items and title are not made on the nav bar.
Also in AppDelegate, I set the method like following:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
UINavigationBar.appearance().barTintColor = UIColor(hex: "00BFA5")
application.statusBarStyle = UIStatusBarStyle.LightContent
return true
}
Any comments are appreciated!
You need to set the title and buttons on CustomLoginVC and not on navVC
I think you should write to below three line try it:
navVC.navigationItem.leftBarButtonItem = nil;
navVC.navigationItem.rightBarButtonItem = nil;
navVC.navigationItem.hidesBackButton = true;
after that try to write:
navVC.navigationItem.setLeftBarButtonItem(backButton, animated: false)
navVC.navigationItem.setRightBarButtonItem(exportButton, animated: false)
OR
self.title = "Your Title"
var homeButton : UIBarButtonItem = UIBarButtonItem(title: "LeftButtonTitle", style: UIBarButtonItemStyle.Plain, target: self, action: "")
var logButton : UIBarButtonItem = UIBarButtonItem(title: "RigthButtonTitle", style: UIBarButtonItemStyle.Plain, target: self, action: "")
self.navigationItem.leftBarButtonItem = homeButton
self.navigationItem.rightBarButtonItem = logButton
Code below is not working for me, can anyone help to figure it out what is wrong?
var image = UIImage(named: "10384605_10152519403846670_5189785375955620548_n.jpg") as UIImage
self.navigationController.navigationBar.setBackgroundImage(image , forBarMetrics:UIBarMetrics)
self.navigationController.navigationBar.setBackgroundImage(image,
forBarMetrics: .Default)
In AppDelegate.swift
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
//Image Background Navigation Bar
let navBackgroundImage:UIImage! = UIImage(named: "backgroundNB.png")
UINavigationBar.appearance().setBackgroundImage(navBackgroundImage, forBarMetrics: .Default)
return true
}
In Swift 3:
If you want to add a repeating image in the background you can make this call in AppDelegate > didFinishLaunchingWithOptions:
let image = UIImage(named: "imageNameInAsset")
UINavigationBar.appearance().setBackgroundImage(image, for: .default)
If you want to add an image to the center of the navigation bar you need to do this in the ViewController > viewWillAppear:
let titleView = UIImageView(image: UIImage(named: "imageNameInAsset"))
self.navigationItem.titleView = titleView
If you want to fill the image in navigation bar just use the code:
self.navigationController?.navigationBar.setBackgroundImage(UIImage(named: "your_Background_Image_Name")?.resizableImage(withCapInsets: UIEdgeInsets.zero, resizingMode: .stretch), for: .default)
let navBackgroundImage:UIImage! = UIImage(named: "navbar_bg")
[UINavigationBar .appearance().setBackgroundImage(navBackgroundImage, forBarMetrics:.Default)]
For Swift 3:
In AppDelegate.swift:
UINavigationBar.appearance().setBackgroundImage(UIImage(named:"pattern.png"),
for: .default)
OR
In viewDidLoad():
self.navigationController?.navigationBar.setBackgroundImage(UIImage(named:"pattern.png"),
for: .default)
set backgroundImage in Navigation controller
self.navigationController?.navigationBar .setBackgroundImage(UIImage(named: "cricket"), for: .default)
if You put the navigation bar hidden for the application you have to show it on view did load or appear by :
override func viewWillAppear(_ animated: Bool) {
print("\n Debugger : View will appear called")
self.navigationController?.isNavigationBarHidden = false
}
if you want your navigation bar only show in a specific view controller you have to disappear the navigation bar by :
override func viewDidDisappear(_ animated: Bool) {
print("\n Debugger : View did disapper called")
self.navigationController?.isNavigationBarHidden = true
}
Navigation bar setup Method
private func navigationBarSetup(){
print("\n Debugger : Navigation Bar setup method called")
self.navigationController!.navigationBar.setBackgroundImage(UIImage(named: "your image name "), for: .default)
let backButton = UIBarButtonItem(image: UIImage(named: "your Image name"), style: .plain, target: self, action: #selector(Your selector method))
backButton.tintColor = UIColor.white
self.navigationItem.leftBarButtonItem = backButton
let rightButton = UIBarButtonItem(image: UIImage(named: "your Image name"), style: .plain, target: self, action: #selector(Your selector method))
backButton.tintColor = UIColor.white
self.navigationItem.rightBarButtonItem = rightButton
}
Add the following code to didFinishLaunchingWithOptions method in AppDelegate.swift:
if let myImage = UIImage(named: "navBarImage.jpg"){
UINavigationBar.appearance().setBackgroundImage(myImage, for: .default)
}
#benLIVE asked for how to do a back button, which I was doing when I found the accepted answer, so I thought I'd leave this here too (if a bit late) b/c if you are going to replace a nav bar icon, you may as well replace all of them!
let cubeIcon = UIImageView(image: yourImage)
cubeIcon.contentMode = .scaleAspectFit
self.navigationItem.backBarButtonItem?.image = cubeIcon.image