i am trying to keep bottom tab bar in children viewcontroller , my issue when i open children window its open without bottom tabs , how i can keep bottom tabs stuck everywhere in the app ?
this is the class of main tabs window ( landing )
class vc_landingPage: UITabBarController , UITabBarControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
}
//Delegate methods
func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
print("Should select viewController: \(String(describing: viewController.title)) ?")
return true;
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let sb2 = UIStoryboard(name: "pools", bundle: nil)
let v1 = sb2.b_pools.instantiateInitialViewController()!
v1.tabBarItem = UITabBarItem( title : "" , image: UIImage(named: "icon-pools-x30"), selectedImage: UIImage(named: "icon-pools-x30-active"))
let sb = UIStoryboard(name: "myProfile", bundle: nil)
let v2 = sb.instantiateInitialViewController()!
v2.tabBarItem = UITabBarItem( title : "" , image: UIImage(named: "icon-profile-x30"), selectedImage: UIImage(named: "icon-profile-x30-active"))
self.viewControllers = [v1,v2]
self.selectedIndex = 1
}
}
Please you must manage the children window in a UINavigationController.
let v1 = sb2.b_pools.instantiateInitialViewController()!
let navi1 = UINavigationController.init(rootViewController: v1)
let v2 = sb.instantiateInitialViewController()!
let navi2 = UINavigationController.init(rootViewController: v2)
self.viewControllers = [navi1,navi2]
Make sure your BOTTOM BAR is not none, make sure it is not set to any of your view controller or your tab bar controller
Related
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.
}
*/
}
I have to customize the tab bar like the picture above. However, I don't know how to customize this point because the name of the item should appear only when the tab bar is selected, and the name of the item should not appear if it is not selected. Please help me.
As an example, it was written with two items.
You can branch to the tag depending on the selected item in didSelect() method.
In viewWillAppear(), I wrote the title of first item because the first item is selected when the app is first launched. (initialization)
I hope my answer is helpful to you.
TabBarController.swift
import UIKit
class TabBarController: UITabBarController, UITabBarControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
self.delegate = self
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
//Setting the UITabBarItem
let tab1 = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(identifier: "ViewController")
let tab1BarItem = UITabBarItem(title: "home", image: UIImage(systemName: "seal"), selectedImage: UIImage(systemName: "seal.fill"))
tab1.tabBarItem = tab1BarItem
tab1.tabBarItem.tag = 0
let tab2 = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(identifier: "SearchViewController")
let tab2BarItem = UITabBarItem(title: "", image: UIImage(systemName: "checkmark.seal"), selectedImage: UIImage(systemName: "checkmark.seal.fill"))
tab2.tabBarItem = tab2BarItem
tab2.tabBarItem.tag = 1
self.viewControllers = [tab1, tab2]
}
override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
if item.tag == 0 { // tab1(home)
item.title = "home"
tabBar.items?[1].title = ""
}
if item.tag == 1 { // tab2(search)
item.title = "search"
tabBar.items?[0].title = ""
}
}
}
Preview
You need to do 2 things
1- To make the the selected tab color green
tabController.tabBar.tintColor = UIColor.green
2- When item is selected listen for UITabBarControllerDelegate and assign items with text set to "" for every unselected item
tabController.tabBar.items = [] // set all items
click the link to view the image
There is something above the navigationbar, and I'm confused on what it is and how to get rid of it.
here is my tabController code
{import UIKit
class TabBarController: UITabBarController, UITabBarControllerDelegate {
override func viewDidLoad() {
delegate = self
authenticateUserAndConfigureView()
}
func setupViewControllers() {
let home = templateNavController(viewController: DiscoverViewController(), image: UIImage(named: "house")!, title: "Home")
let search = templateNavController(viewController: SearchViewController(), image: UIImage(named: "search")!, title: "Discover")
let problem = templateNavController(viewController: NewProblemViewController(), image: UIImage(named:"addproblem")!, title: "Add New Problem")
let chat = templateNavController(viewController: MessageViewController(), image: UIImage(named: "chat")!, title: "Chat")
let profile = templateNavController(viewController: ProfileViewController(), image: UIImage(named: "profile")!, title: "Profile")
self.viewControllers = [home, search, problem, chat, profile]
}
func authenticateUserAndConfigureView() {
DispatchQueue.main.async {
if Auth.auth().currentUser == nil {
let navController = UINavigationController(rootViewController: LoggedOut())
navController.modalPresentationStyle = .fullScreen
self.present(navController, animated: true, completion: nil)
} else {
self.setupViewControllers()
}
}
}
func templateNavController(viewController: UIViewController, image: UIImage, title: String) -> UINavigationController {
let navController = UINavigationController(rootViewController: viewController)
navController.tabBarItem.image = image
navController.navigationBar.backgroundColor = .white
navController.tabBarItem.title = title
return navController
}
}
}
You can always use 'Debug View Hierarchy' xCode tool to see views hierarchy in a screen.
Just run the app on a simulator or device and click 'Debug View Hierarchy' when your screen is active.
Here you can rotate screen and see all active layers. Once you select a layer you can check it name and position in hierarchy on the left bar.
Hey Guys I figured it out! My mistake was that I cast my original TabBarController as a UINavigationController before setting the view controllers on there. Thus there was a navigation bar from the mistake UINavController and another navigation bar from the navigation controller that I cast on each view controller.
I am working without Storyboards.
After the successful login, I'd like to add a tabBar into my viewControllers.
I created another viewController called tabBar controller with the code:
class TabBarController: UITabBarController,UITabBarControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
self.delegate = self
}
override func viewWillAppear(_ animated: Bool) {
// Create Tab one
let tabOne = Home()
let tabOneBarItem = UITabBarItem(title: "Collection", image: #imageLiteral(resourceName: "matchTabIcon"), selectedImage: #imageLiteral(resourceName: "matchTabIconSelected"))
tabOne.tabBarItem = tabOneBarItem
// Create Tab two
let tabTwo = ScoutingVC()
let tabTwoBarItem2 = UITabBarItem(title: "Scouting", image: #imageLiteral(resourceName: "scouting"), selectedImage:#imageLiteral(resourceName: "scoutingSelected"))
tabTwo.tabBarItem = tabTwoBarItem2
self.viewControllers = [tabOne, tabTwo]
}
// UITabBarControllerDelegate method
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
print("Selected \(viewController.title!)")
}
}
What is the correct way to add this to all of my VCs?
I tried
self.vc.addSubView(tabBarController)
and also to create a func() in the first VC (index: 0), but either the tabBar is not there, or if there, doesn't switch between viewControllers.
func showTabBarController() {
// Create Tab one
let home = Home()
let homeTabBarItem = UITabBarItem(title: "Collection", image: #imageLiteral(resourceName: "matchTabIcon"), selectedImage: #imageLiteral(resourceName: "matchTabIconSelected"))
home.tabBarItem = homeTabBarItem
let navHome = UINavigationController.init(rootViewController: home)
// Create Tab two
let scouting = ScoutingVC()
let scoutingTabBarItem = UITabBarItem(title: "Scouting", image: #imageLiteral(resourceName: "scouting"), selectedImage: #imageLiteral(resourceName: "scoutingSelected"))
scouting.tabBarItem = scoutingTabBarItem
let navScouting = UINavigationController.init(rootViewController: scouting)
//showTabBar
tabBarCnt.viewControllers = [navHome, navScouting]
self.view.addSubview(tabBarCnt.tabBar)
}
Instead of using self.vc.addSubView(tabBarController) use present(TabBarController(), animated: false, completion: nil)
I'm trying to customize the title of my More button in my UITabBarController as I'm doing the app in another language. I subclassed UITabBarController to be able to access the tabBarController property. Unfortunately, it's always nil whether I put it in viewDidLoad or viewDidAppear(_). Any thoughts on how I can edit it?
import UIKit
class ControllerVC: UITabBarController {
let uiManager = UIManager()
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(_ animated: Bool) {
if let tabBarItem = tabBarController?.moreNavigationController.tabBarItem {
let deselectedImage = tabBarItem.image
let selectedImage = tabBarItem.selectedImage
tabBarController!.moreNavigationController.tabBarItem = UITabBarItem(title: "بیشتر", image: deselectedImage, selectedImage: selectedImage)
} else {
uiManager.showActivityIndicator(self)
}
}
}
The problem is not with moreNavigationController. The problem is with tabBarController. Your class is a UITabBarController. A tab bar controller's tabBarController property is always nil.
Just do:
let tabBarItem = moreNavigationController.tabBarItem
let deselectedImage = tabBarItem.image
let selectedImage = tabBarItem.selectedImage
moreNavigationController.tabBarItem = UITabBarItem(title: "بیشتر", image: deselectedImage, selectedImage: selectedImage)