NavigationBar can't display title - ios

I create a UINavigationController object, but it can't set the title.
class LogInSwitchingViewController: UINavigationController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.view.backgroundColor = UIColor.white
self.navigationItem.title = "This is title"
self.navigationBar.tintColor = UIColor.black
let vc1 = UIViewController()
vc1.view.backgroundColor = UIColor.brown
self.pushViewController(vc1, animated: true)
}

You need to update the title property of the visible view controller, not the navigation controller itself:
let vc1 = UIViewController()
vc1.title = "This is title"
vc1.view.backgroundColor = UIColor.brown
self.pushViewController(vc1, animated: true)

Related

Config Navigation bar only work if viewControllers are created inside viewWillAppear in UITabBarController

I have a UITabBarController with 2 ViewControllers: HomeViewController and ProfileViewController
Inside HomeViewController, I have to change the NavigationBar appearance with the following code:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if let nav = self.navigationController {
nav.navigationBar.layer.zPosition = 0
}
let logo = UIImage(named: "plentinaText")?.withRenderingMode(.alwaysTemplate)
let container = UIView(frame: CGRect(x: 0, y: 0, width: 1000, height: 0))
let imageView = UIImageView(image: logo)
imageView.tintColor = .white
imageView.contentMode = .scaleAspectFit
container.addSubview(imageView)
imageView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
imageView.topAnchor.constraint(equalTo: container.topAnchor),
imageView.bottomAnchor.constraint(equalTo: container.bottomAnchor, constant: -10),
imageView.centerXAnchor.constraint(equalTo: container.centerXAnchor),
imageView.widthAnchor.constraint(equalToConstant: view.frame.width)
])
self.tabBarController?.navigationItem.titleView = container
}
Problem is, this block of code only work if I create HomeViewController ProfileViewController inside viewWillAppear in UITabBarController.
If I put it in ViewDidLoad, it don't even have a NavigationBar. But when I push to another vc and go back to HomeViewController, the Nav bar will work as I wanted.
//
// HomeTabbarController.swift
// Plentina
//
// Created on 10/29/21.
//
import UIKit
class HomeTabbarController: UITabBarController, UITabBarControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
delegate = self
UITabBar.appearance().barTintColor = PlenitaColors.buttonBackGround // your color
if #available(iOS 13.0, *) {
UITabBar.appearance().unselectedItemTintColor = UIColor.systemGray4
} else {
UITabBar.appearance().unselectedItemTintColor = UIColor.lightGray
}
UITabBar.appearance().tintColor = .white
if #available(iOS 15.0, *) {
let appearance = UITabBarAppearance()
appearance.configureWithOpaqueBackground()
appearance.backgroundColor = PlenitaColors.buttonBackGround
tabBar.standardAppearance = appearance
tabBar.scrollEdgeAppearance = appearance
}
// Do any additional setup after loading the view.
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// tabbar 1
let storyboard = UIStoryboard(name: "Custom", bundle: nil)
let viewController = storyboard.instantiateViewController(withIdentifier: "photo") as? HomeViewController
let item1 = viewController
let unselectedIcon1 = UIImage(named: "tabbarHome")?.withRenderingMode(.alwaysTemplate)
let selectedIcon1 = UIImage(named: "tabbarHome")!.withRenderingMode(.alwaysTemplate)
let icon1 = UITabBarItem(title: "Loans", image: unselectedIcon1, selectedImage: selectedIcon1)
item1!.tabBarItem = icon1
// tabbar 2
let unselectedIcon2 = UIImage(named: "tabbarProfile")?.withRenderingMode(.alwaysTemplate)
let selectedIcon2 = UIImage(named: "tabbarProfile")!.withRenderingMode(.alwaysTemplate)
let item2 = ProfileViewController()
let icon2 = UITabBarItem(title: "Profile", image: unselectedIcon2, selectedImage: selectedIcon2)
item2.tabBarItem = icon2
let controllers = [item1!, item2] // array of the root view controllers displayed by the tab bar interface
self.viewControllers = controllers
}
// Delegate methods
func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
print("Should select viewController: \(viewController.title ?? "") ?")
return true
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}
*/
}
I found a workaround. I just need to leave self.viewControllers = controllers in viewWillAppear and move the rest to ViewDidLoad, but I still don't know why?
class HomeTabbarController: UITabBarController, UITabBarControllerDelegate {
var controllers: [Any]?
override func viewDidLoad() {
super.viewDidLoad()
delegate = self
UITabBar.appearance().barTintColor = PlenitaColors.buttonBackGround // your color
if #available(iOS 13.0, *) {
UITabBar.appearance().unselectedItemTintColor = UIColor.systemGray4
} else {
UITabBar.appearance().unselectedItemTintColor = UIColor.lightGray
}
UITabBar.appearance().tintColor = .white
if #available(iOS 15.0, *) {
let appearance = UITabBarAppearance()
appearance.configureWithOpaqueBackground()
appearance.backgroundColor = PlenitaColors.buttonBackGround
tabBar.standardAppearance = appearance
tabBar.scrollEdgeAppearance = appearance
}
// tabbar 1
let storyboard = UIStoryboard(name: "Custom", bundle: nil)
let viewController = storyboard.instantiateViewController(withIdentifier: "photo") as? HomeViewController
let item1 = viewController
let unselectedIcon1 = UIImage(named: "tabbarHome")?.withRenderingMode(.alwaysTemplate)
let selectedIcon1 = UIImage(named: "tabbarHome")!.withRenderingMode(.alwaysTemplate)
let icon1 = UITabBarItem(title: "Loans", image: unselectedIcon1, selectedImage: selectedIcon1)
item1!.tabBarItem = icon1
// tabbar 2
let unselectedIcon2 = UIImage(named: "tabbarProfile")?.withRenderingMode(.alwaysTemplate)
let selectedIcon2 = UIImage(named: "tabbarProfile")!.withRenderingMode(.alwaysTemplate)
let item2 = ProfileViewController()
let icon2 = UITabBarItem(title: "Profile", image: unselectedIcon2, selectedImage: selectedIcon2)
item2.tabBarItem = icon2
controllers = [item1!, item2] // array of the root view controllers displayed by the tab bar interface
// Do any additional setup after loading the view.
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.viewControllers = controllers as? [UIViewController]
}
// Delegate methods
func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
print("Should select viewController: \(viewController.title ?? "") ?")
return true
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}
*/
}

Present Modally UIViewController From UITabBarController Programmatically

Hi everyone I need to present a View Controller modally when the user selects the index 1 of my Tab bar.
I created a UITabBarController class where I instantiate all the view controllers to be shown with the tabBar
In this part of the code I manage the modal presentation of the view controller for the index 1 of the tabBar
The problem is that when I select index 1 the VCIndex1 controller is called twice ... once for the normal display of the tabBar and another time for the modal presentation
How can I present VCIndex1 modally without the tab bar calling the controller x2 times?
class TabBarController: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
delegate = self
tabBar.barTintColor = UIService.Color.backgroundColor
tabBar.isTranslucent = false
tabBar.tintColor = UIService.Color.primaryColor
tabBar.selectedItem?.badgeColor = UIService.Color.secondaryColor
tabBar.unselectedItemTintColor = UIService.Color.tertiaryColor
tabBar.shadowImage = UIImage()
let vcIndex0 = UINavigationController(rootViewController: VC0())
vcIndex0 = UIImage(systemName: "rosette")
let vcIndex1 = UINavigationController(rootViewController: VC1())
vcIndex1 = UIImage(systemName: "plus.square.on.square")
let vcIndex2 = UINavigationController(rootViewController: VC2())
vcIndex2 = UIImage(systemName: "tag")
viewControllers = [vcIndex0, vcIndex1, vcIndex2]
}
override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
let indexOfTab = tabBar.items?.firstIndex(of: item)
if indexOfTab == 1 {
let vc = VC1()
vc = .fullScreen
present(vc, animated: true, completion: nil)
}
}
}
You probably want to implement shouldSelect (Apple Docs) and handle your tab-detection and modal presentation there.
Give this a try:
class TabBarController: UITabBarController, UITabBarControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
delegate = self
tabBar.barTintColor = .lightGray // UIService.Color.backgroundColor
tabBar.isTranslucent = false
tabBar.tintColor = .green // UIService.Color.primaryColor
tabBar.selectedItem?.badgeColor = .blue // UIService.Color.secondaryColor
tabBar.unselectedItemTintColor = .cyan // UIService.Color.tertiaryColor
tabBar.shadowImage = UIImage()
let vcIndex0 = UINavigationController(rootViewController: VC0())
vcIndex0.tabBarItem = UITabBarItem(title: "0", image: UIImage(systemName: "rosette"), tag: 0)
// just create a plain UIViewController here (it will never be seen)
//let vcIndex1 = UINavigationController(rootViewController: VC1())
let vcIndex1 = UIViewController()
vcIndex1.tabBarItem = UITabBarItem(title: "1", image: UIImage(systemName: "plus.square.on.square"), tag: 0)
let vcIndex2 = UINavigationController(rootViewController: VC2())
vcIndex2.tabBarItem = UITabBarItem(title: "2", image: UIImage(systemName: "tag"), tag: 0)
viewControllers = [vcIndex0, vcIndex1, vcIndex2]
}
func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
if viewController == tabBarController.viewControllers?[1] {
let vc1 = VC1()
vc1.modalPresentationStyle = .fullScreen
present(vc1, animated: true, completion: nil)
return false
}
return true
}
override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
// if you want to do something based on selected tab
if let indexOfTab = tabBar.items?.firstIndex(of: item) {
print("didSelect:", indexOfTab)
}
}
}
class VC0: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .red
}
}
class VC1: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .green
let tap = UITapGestureRecognizer(target: self, action: #selector(dismissMe))
view.addGestureRecognizer(tap)
}
#objc func dismissMe() -> Void {
dismiss(animated: true, completion: nil)
}
}
class VC2: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .blue
}
}

Swift - UITabBarController as ChildViewController is not working

I need to add UITabBarController as a subview of RootViewController, but that UITabBarController can't be touched.
Here is my code. How can i fix it?
func addSubviewToSelf(){
var tabVC = TabBarVC()
addChildViewController(tabVC)
self.view.addSubview(tabVC.view)
tabVC.didMove(toParentViewController: self)
tabVC.view.snp.makeConstraints{ (make) in
make.top.bottom.left.right.equalTo(self.view)
}
}
Here is the simplified version of adding UITabBarController as childView of UIViewController, I'm using NSLayoutAnchor API in place of SnapKit
import UIKit
class RootViewController: UIViewController {
override func loadView() {
view = UIView()
view.backgroundColor = .white
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
addChildVC()
}
func addChildVC() {
let tabBarVC = TabBarVC()
addChild(tabBarVC)
view.addSubview(tabBarVC.view)
tabBarVC.view.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
tabBarVC.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
tabBarVC.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
tabBarVC.view.bottomAnchor.constraint(equalTo: view.bottomAnchor),
tabBarVC.view.topAnchor.constraint(equalTo: view.topAnchor)
])
tabBarVC.didMove(toParent: self)
}
}
The UITabBarController subclass is below
class TabBarVC: UITabBarController, UITabBarControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
delegate = self
// Do any additional setup after loading the view.
configureTabBarItems()
}
func configureTabBarItems() {
let vc1 = UIViewController()
vc1.view.backgroundColor = .orange
vc1.tabBarItem = UITabBarItem(tabBarSystemItem: .search, tag: 0)
let vc2 = UIViewController()
vc2.view.backgroundColor = .yellow
vc2.tabBarItem = UITabBarItem(tabBarSystemItem: .bookmarks, tag: 1)
let navigationController1 = UINavigationController(rootViewController: vc1)
let navigationController2 = UINavigationController(rootViewController: vc2)
setViewControllers([navigationController1, navigationController2], animated: false)
tabBar.tintColor = .red
tabBar.unselectedItemTintColor = .black
}
}
As you have not given UITabBarController subclass implementation, you may create some UIViewControllers and assign it to setViewControllers(_ viewControllers::[UIViewControllers]?, animated: Bool) method. Also set tintColor and unselectedItemTintColor properties and check if works for you. Finally Clean Build project and run, it should work for you.
If the Tabbarvc is about for all App , I think you can call in AppDelegate. Write this code in didFinishLaunch in AppDelegate
window = UIWindow(frame: UIScreen.main.bounds)
let storyboard = UIStoryboard(name: "TabBarStoryBoard", bundle: Bundle.main)
let viewController = storyboard.instantiateInitialViewController()
window?.rootViewController = viewController
window?.makeKeyAndVisible()
return true

How to set up a title at the top of a ViewController

In my app I have a tabBarViewController, and this is the first bar:
class FirstViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.white
}
override func viewWillAppear(_ animated: Bool) {
self.navigationItem.title = "RECENTS"
}
}
this is the custom class:
class CustomTabBar: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
let firstVC = FirstViewController()
let secondVC = SecondViewController()
let thirdVC = ThirdViewController()
firstVC.tabBarItem.title = "RECENT"
secondVC.tabBarItem.title = "MAP"
thirdVC.tabBarItem.title = "SETTINGS"
firstVC.title = "RECENT"
secondVC.title = "MAP"
thirdVC.title = "SETTINGS"
viewControllers = [firstVC,secondVC,thirdVC]
}
}
So my question is: How can I put a title at the top of the view controller?
In the previous code I tried, but it's not working!
Something like this:
The title property is shown when a view controller is wrapped in a UINavigationController. Here's some code replacing the last line (i.e. the viewControllers assignment) in of your example that should do the trick:
let firstNC = UINavigationController(rootViewController: firstVC)
let secondNC = UINavigationController(rootViewController: secondVC)
let thirdNC = UINavigationController(rootViewController: thirdVC)
viewControllers = [firstNC,secondNC,thirdNC]
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
self.tabBarController?.navigationItem.title = "My Title"
}
This should work. I hope it helps you.
Or if you can try this.
let vc3 = UINavigationController(rootViewController: SearchVC())
vc3.tabBarItem.image = UIImage(named: "vyhledavani")
vc3.title = "Vyhledat"
vc3.tabBarItem.tag = 2
viewControllers = [vc3, ...]

Navigation controller title not showing up?

So when I have my OptionsViewController as the rootViewController in the AppDelegate didFinishLaunchingWithOptions...
let rootVC = OptionsViewController()
let navigationController = UINavigationController(rootViewController: rootVC)
navigationController.navigationBar.barTintColor = .white
navigationController.navigationBar.isTranslucent = false
navigationController.navigationBar.tintColor = .black
self.window = UIWindow(frame: UIScreen.main.bounds)
self.window!.rootViewController = navigationController
self.window?.makeKeyAndVisible()
...setting the title of the OptionViewController works if I do this in viewDidLoad():
title = "Route Options"
But when I push OptionsViewController onto the navigation stack the title doesn't show up.
I.e. if I start w/ a different view as the rootViewController in AppDelegate:
let rootVC = HomeViewController()
let navigationController = UINavigationController(rootViewController: rootVC)
navigationController.navigationBar.barTintColor = .white
navigationController.navigationBar.isTranslucent = false
navigationController.navigationBar.tintColor = .black
self.window = UIWindow(frame: UIScreen.main.bounds)
self.window!.rootViewController = navigationController
self.window?.makeKeyAndVisible()
And in HomeViewController I push my OptionViewController like this:
let optionsVC = OptionsViewController()
navigationController?.pushViewController(optionsVC, animated: true)
The title does not show up!
The only way I've managed for the title to show up is by doing (in OptionViewController)
navigationController?.navigationBar.topItem?.title = "Route Options"
But it shows up as the back button rather than in the middle, which is not what I want.
If anyone could tell me how I could set the title so that it is on the middle of the navigation bar when it is pushed onto the navigationController stack that would be great!
Code
AppDelegate.swift
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let rootVC = HomeViewController()
let navigationController = UINavigationController(rootViewController: rootVC)
let barAppearance = UINavigationBar.appearance()
barAppearance.barTintColor = UIColor.blue
barAppearance.tintColor = UIColor.white
barAppearance.titleTextAttributes = [NSForegroundColorAttributeName: UIColor.white]
self.window = UIWindow(frame: UIScreen.main.bounds)
self.window!.rootViewController = navigationController
self.window?.makeKeyAndVisible()
return true
}
HomeViewController.swift
class HomeViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, DestinationDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let optionsVC = OptionsViewController()
self.definesPresentationContext = false //else going to try and present optionVC on homeVC when in optionVC
navigationController?.pushViewController(optionsVC, animated: true)
}
tableView.deselectRow(at: indexPath, animated: true)
}
}
OptionsViewController.swift
class OptionsViewController: UIViewController, UITableViewDelegate, UITableViewDataSource,
DestinationDelegate, SearchBarCancelDelegate,UISearchBarDelegate,
CLLocationManagerDelegate {
override func viewDidLoad() {
self.title = "Route Options"
}
You need to set the navigationItem.title to desired value. If you want an image you set navigationItem.titleView
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.title = "Your title here"
}
For others coming here based on the title, don't forget to set your ViewController class in IB to the appropriate Swift file.
After doing that I was able to set the title without a problem using
self.navigationItem.title = "my title"
or
self.title = "my title"
Try it:
In HomeViewController:
let optionsVC = OptionsViewController()
navigationController?.viewControllers = [optionsVC]
And in your OptionsViewController:
override func viewDidLoad() {
super.viewDidLoad()
navigationController?.navigationBar.isTranslucent = false
navigationItem.title = "Your Title"
}
first you need to set UINavigationBar color and text color .
try this in didFinishLaunchingWithOptions.
let barAppearance = UINavigationBar.appearance()
barAppearance.barTintColor = UIColor.blue
barAppearance.tintColor = UIColor.white
barAppearance.titleTextAttributes = [NSForegroundColorAttributeName: UIColor.white]
if you want to remove the string after backbutton
add these too
let barItemAppearace = UIBarButtonItem.appearance()
barItemAppearace.setBackButtonTitlePositionAdjustment(UIOffsetMake(0, -60), for:UIBarMetrics.default)
And just set your title in viewDidLoad() or
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.title = "Your Title"
}
Just add the below line to set the title for navigation item
self.title = "Title 1"
Using Objective-C I also had the problem that it didn't show me the title but going to the next Scene the title appeared next to the back button.
I don't really know why, but I solved it by programming the relative ViewController of that Scene in Swift instead of Objective-C.
After that, it was enough to use the command:
self.title = "My Title"
and so I was able to write what I want programmatically, using if-statement or other methodologies.
Maybe this could be useful to someone who has this problem with Objective-C.
All you need is initialisation navigationItem.title by string containing any printable symbols in viewDidLoad function. String like "" or " " will not worked.
Like this:
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.title = "."
}
Then code navigationItem.title = "Any string" will work well anywhere in your ViewController.
This bag was fixed in iOs 16.2

Resources