Create iOS Tab bar dynamically - ios

I want to create tab bar dynamically based on server response. Tab count will change every time. And how to design the views all view have the same design only data will change

suppose you have vc1,vc2,vc3
self.tabBarController.viewControllers = [vc1,vc2,vc3]

Create a separate class for tab bar controller. Create a method there which must return tab bar controller.
In the method, pass an array, on each index it will contains the tab bar name, image, selected image, view controller.

You'll need to make your server call BEFORE you set up the view controller. If it is your first view, you will need to do this in viewdidload and perhaps set up an activity indicator. If not you need to have some sort of loading screen / make your call in the immediately prior to your tabBar.

Put This Method in Utilities Class :
class func setupTabBarController(tabbarController: UITabBarController) {
let hOmeVC = HomePageViewController()
let skriblBoxVC = MySkribViewController()
let searchVC = SearchViewController()
tabbarController.tabBar.isExclusiveTouch = true
tabbarController.view.backgroundColor = UIColor.white
// Creating navigation Controller and putting them in tabBarController because without it we will not be able to push viewController
let homeNavigationController = UINavigationController()
let skriblBoxNavigationController = UINavigationController()
let searchNavigationController = UINavigationController()
tabbarController.viewControllers = []
tabbarController.tabBar.isTranslucent = false
tabbarController.viewControllers = [homeNavigationController, skriblBoxNavigationController, searchNavigationController]
tabbarController.selectedIndex = 0
tabbarController.tabBar.items![0].image = #imageLiteral(resourceName: "tab_home")
tabbarController.tabBar.items![1].image = #imageLiteral(resourceName: "tab_box")
tabbarController.tabBar.items![SBModules.SEARCH.rawValue].image = #imageLiteral(resourceName: "tab_search")
tabbarController.tabBar.items![2].image = #imageLiteral(resourceName: "tab_cart")
tabbarController.tabBar.items![0].selectedImage = #imageLiteral(resourceName: "tab_home_selected")
tabbarController.tabBar.items![1].selectedImage = #imageLiteral(resourceName: "tab_box_selected")
tabbarController.tabBar.items![2].selectedImage = #imageLiteral(resourceName: "tab_search_selected")
tabbarController.tabBar.barTintColor = UIColor.white
tabbarController.tabBar.tintColor = UIColor.tabBarBadgeColorWithAlpha()
tabbarController.tabBar.itemPositioning = .automatic
tabbarController.tabBar.itemSpacing = 2.0
tabbarController.tabBarItem.title = nil
if let items = tabbarController.tabBar.items {
for item in items {
item.title = ""
item.imageInsets = UIEdgeInsetsMake(6, 0, -6, 0);
}
}
}
and class this method form viewController
Like
let tabbarController = UITabBarController()
func loadHomePage() {
Utilities.setupTabBarController(tabbarController: self.tabbarController)
self.updateBadgeValueToCart()
self.window?.rootViewController = self.tabbarController
}

Related

TabBarController icon not showing until clicked - No Storyboard

Ive added a number of tabs to a tabbar controller by
private func setupViewControllers() {
let layout = UICollectionViewFlowLayout()
let layout2 = UICollectionViewFlowLayout()
let controllers = [
VLCAudioViewController(services: services),
VLCDJViewController(collectionViewLayout: layout),
VLCUserViewController(collectionViewLayout: layout2)
]
tabBarController.viewControllers = controllers.map { UINavigationController(rootViewController: $0) }
}
And what happens is the last tab doesnt show its icon until clicked.
before click
after click
It seems to be because im adding a second collectionViewLayout as if i change the type it appears.
As I see your above code. I guest you set tabbar item icon in viewDidLoad of these ViewController.
Please set icon for tabbar item when setup viewControllers of tabbarController
UPDATE: Try like
private func setupViewControllers() {
let layout = UICollectionViewFlowLayout()
let layout2 = UICollectionViewFlowLayout()
let vlcUserVC = VLCUserViewController(collectionViewLayout: layout2)
// Set tabbar item
vlcUserVC.tabbarItem = UITabBarItem.init(title: "User", image: UIImage(named: "user-icon"), selectedImage: UIImage(named: "user-selected"))
let controllers = [
VLCAudioViewController(services: services),
VLCDJViewController(collectionViewLayout: layout),
vlcUserVC
]
tabBarController.viewControllers = controllers.map { UINavigationController(rootViewController: $0) }
}

How to fix disappearing Tab Bar Controller when changing View Controller initialized from code

I'm struggling with the problem which is when I'm switching view controllers connected with push segue then everything works as expected. The problem is that I have a search bar that executes Table View Controller from code and when I select the cell from that Table View Controller the next view controller is without tab bar.
I am using Table View Controller as a view that displays results from search bar. When I am selecting cell (result from searching) then I am changing view controller showing the results. But this one is done from storyboard.
I know that the Table View Controller executed from code does not "inherits" tab bar from previous controllers through the navigation bar. But this one should be executed from code.
Initialize Search Result Controller
override func viewDidLoad() {
super.viewDidLoad()
self.definesPresentationContext = true
tableView.separatorStyle = .none
self.extendedLayoutIncludesOpaqueBars = true
refreshControlUI = Refresher.configureRefresher()
tableView.refreshControl = refreshControlUI
refreshControlUI.addTarget(self, action: #selector(pullToRefresh), for: .valueChanged)
// Initialize search table
let priceSearchTable = storyboard?.instantiateViewController(withIdentifier: "CoinSearchTable") as! CoinSearchTableViewController
// asignle pricetable as a search results controller
resultSearchController = UISearchController(searchResultsController: priceSearchTable)
resultSearchController?.searchResultsUpdater = priceSearchTable
// Make navigation bar large
self.navigationController?.navigationBar.prefersLargeTitles = true
self.navigationController?.navigationItem.largeTitleDisplayMode = .never
self.navigationItem.searchController = resultSearchController
// customize search bar
let searchBar = resultSearchController!.searchBar
searchBar.sizeToFit()
searchBar.placeholder = "Search for coins"
resultSearchController?.hidesNavigationBarDuringPresentation = false
resultSearchController?.dimsBackgroundDuringPresentation = true
}
This code is responsible just for passing values to selected view controller.
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if shownAllCoins.count > 0 {
let coinString = shownAllCoins[indexPath.row]
picked = PickedCoin(symbols: [coinString])
picked.delegate = self
navigationController?.setNavigationBarHidden(false, animated: true)
picked.getDetail(name: coinString)
coin = picked.coins[0]
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "goToDetailsFromSearch" {
if let coin = sender as? [Any]{
if let SearchVC = segue.destination as? DetailPriceViewController{
SearchVC.coin = coin[0] as? Coin
SearchVC.isFromSearching = coin[1] as! Bool
}
}
}
}
Also In Detail View Controller I had to create navigation bar programmatically in case if the segue was from the Search Result Controller.
func addNavBar() {
view.backgroundColor = UIColor(hex: 0x001f3e)
let navBar: UINavigationBar = UINavigationBar(frame: CGRect(x: 0, y: 20, width: view.frame.size.width, height: 44))
navBar.barTintColor = UIColor(hex: 0x001f3e)
navBar.isTranslucent = false
self.view.addSubview(navBar);
guard let coin = coin else {return}
let navItem = UINavigationItem(title: "\(coin.symbol)")
let backButton = UIButton(type: .custom)
let textAttributes = [NSAttributedString.Key.foregroundColor:UIColor.white]
navBar.titleTextAttributes = textAttributes
saveButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.bookmarks, target: self, action: #selector(self.selectorName(_ :)));
backButton.setTitle("Back", for: .normal)
backButton.setTitleColor(backButton.tintColor, for: .normal) // You can change the TitleColor
backButton.addTarget(self, action: #selector(self.backAction(_:)), for: .touchUpInside)
navItem.leftBarButtonItem = UIBarButtonItem(customView: backButton)
navItem.rightBarButtonItem = saveButton
navBar.setItems([navItem], animated: false)
}
Bellow is screenshot of storyboard connection. This storyboard without navigation bar is of course this SearchResultController (Table View Controller that displays results and switches to the detail controller).
What is the best way to set tab bar as a root controller or something. I just need the tab bar to be in all view controller doesn't matter if the controllers are initialize from storyboard or code.
I am trying all day to fix this but I don't know how..
I appreciate every help!
Thanks!
Ok, the problem was with segues. I tried to pass the value from another Controller, that has nothing in common with previous one so that was obvious that navigation bar and tab bar wasn't there. While dealing with separate serchable view controller, there should be added delegation, to pass the vale back to Main Controller. When interacting with searchable view controller, the procedure to pass the value to another view controller in my case looks like this:
When I start typing on my Main Controller the new Searchable View Controller Appear
When I find the item I needed Im selecting it by didSelectedRowAt
I'm Passing the selected value through the delegate function
Added delegate to Main Controller from where should be done segue
Now it works like it supposed to.
The simple code looks like this:
protocol SearchTableDelegate {
func passSelectedValue(selected stock: String)
}
In Searchable View Controller declare:
var delegate: SearchTableDelegate!
In DidSelectedRowAt:
delegate.passSelectedValue(selected: selectedValue)
Now in Main Controller:
class MainTableViewController: UITableViewController, SearchTableDelegate {...}
And use the function from protocol:
func passSelectedValue(selected value: String) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
if let destinationVC = storyboard.instantiateViewController(withIdentifier: "details") as? DetailsViewController{
destinationVC.value = value
self.navigationController?.pushViewController(destinationVC, animated: true)
}
}
Also when declaring the SearchableViewController in MainController don't forget to assign delegate from Searchable to self:
searchableTableController.delegate = self

Creating UITabBarController programmatically, only one Tab is showing up

I have a TabBarCoordinator, thats contains a UITabBarController.
I want to add two UINavigationController (CoinPage and Top/Flop), but only one is showing up in the Tab. I thought I have set up everything the right way and I tried some other stuff but I can not get it to work.
This is my code:
class TabBarCoordinator: Coordinator {
var dependencys: DependencyManager
let tabBarController: UITabBarController
var tabCoordinators = [Tabs: Coordinator]()
var navigationController: UINavigationController
init(navigationController: UINavigationController, persistenceCentral: PersistenceCentral, dependencys: DependencyManager) {
self.tabBarController = UITabBarController()
self.navigationController = navigationController
self.dependencys = dependencys
var controllers: [UIViewController] = []
tabCoordinators[.topFlop] = TopFlopCoordinator(navigationController: navigationController, dependencys: dependencys)
tabCoordinators[.coinPage] = CoinPageCoordinator(dependencys: dependencys, navigationController: navigationController)
let coinPageVC = tabCoordinators[.coinPage]!.navigationController
coinPageVC.tabBarItem = UITabBarItem(title: "Coinpage", image: nil, tag: 0)
let topFlopVC = tabCoordinators[.topFlop]!.navigationController
topFlopVC.tabBarItem = UITabBarItem(title: "Top/Flop", image: nil, tag: 1)
controllers.append(topFlopVC)
controllers.append(coinPageVC)
tabBarController.viewControllers = controllers
tabBarController.tabBar.isTranslucent = false
tabCoordinators[.topFlop]?.start()
tabCoordinators[.coinPage]?.start()
}
func start() {
}
}
I did some research, for example he sets up the tabs in a similar way:
https://medium.com/#satindersingh71/uitabbarcontroller-programmatically-2a3df63607f1
So I do not understand why it is not working.
These 2 lines return the same object
let coinPageVC = tabCoordinators[.coinPage]!.navigationController
let topFlopVC = tabCoordinators[.topFlop]!.navigationController
so the last overwrite settings of the first and it shown lonely , you have to make sure that you create 2 separate navigation objects

How can I set rootview of a viewcontroller when I have set Tabbar in appdelegate swift?

I have set UITabBarController in AppDelegate and I have set the root view to tab bar object. But I need to set root view to another view controller without losing the functionalities of tab bar. How can I achieve that?
let vc1 = ConstituencyViewController()
//vc1.view.backgroundColor = UIColor.orange
vc1.tabBarItem.title = "Search"
vc1.tabBarItem.image = UIImage(named: "Search")
// Set up the second View Controller
let vc2 = ConstDetailViewController()
//vc2.view.backgroundColor = UIColor.purple
vc2.tabBarItem.title = "User"
vc2.tabBarItem.image = UIImage(named: "Street View")
// Set up the Tab Bar Controller to have two tabs
let tabBarController = UITabBarController()
tabBarController.viewControllers = [vc1, vc2]
// Make the Tab Bar Controller the root view controller
window?.rootViewController = tabBarController
window?.makeKeyAndVisible()
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let vc1 = ConstDetailViewController()
//vc1.view.backgroundColor = UIColor.orange
vc1.tabBarItem.title = "Search"
vc1.tabBarItem.image = UIImage(named: "Search")
let vc2 = OptionsViewController()
vc2.tabBarItem.title = "Search"
vc2.tabBarItem.image = UIImage(named: "Street View")
// Set up the second View Controller
//vc2.view.backgroundColor = UIColor.purple
// Set up the Tab Bar Controller to have two tabs
let tabBarController = UITabBarController()
tabBarController.viewControllers = [vc1,vc2]
appDelegate.window?.rootViewController = tabBarController
appDelegate.window?.makeKeyAndVisible()

Same View controller in Tab bar controller for 4 tabs is giving wrong selected tabcontroller selected index

I am trying to make a template for my app... lets say my app loads the same view controller which has a CollectionView for 4 tabs. According to selected index, I have to load the contents into collection view. I am setting up the tab bar manually from Appdelegate. My question is Is this possible like instantiating same viewcntroller for all 4 tabs of Tabbarcontroller at a time. if yes, how will i know correctly that which index is selected?
Code for tabBarcontroller in Appdelegate
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
let tabBarController = UITabBarController()
let storyboard : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let firstImage = UIImage(named: "image1")
let secondImage = UIImage(named: "image2")
var controllers = [UIViewController]()
for var i = 0; i < self.myList.count; i++ {
let vc : ViewControllerTwo = storyboard.instantiateViewControllerWithIdentifier("view1") as! ViewControllerTwo
if(i == 0 || i == 3)
{
vc.tabBarItem = UITabBarItem(
title: self.myList[i],
image: firstImage,
tag: i)
controllers.append(vc)
}
else
{
vc.tabBarItem = UITabBarItem(
title: self.myList[i],
image: secondImage,
tag: i)
controllers.append(vc)
}
}
self.tabBarController.viewControllers = controllers
self.window?.rootViewController = self.tabBarController
self.self.window?.rootViewController = self.tabBarController
self.window?.makeKeyAndVisible()
If you set your class as the delegate for your tab bar controller, you will get a call to the didSelectViewController delegate method. You can then use your controllers array to determine the index;
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
let tabBarController = UITabBarController()
tabBarController.delegate = self
func tabBarController(_ tabBarController: UITabBarController,
didSelectViewController viewController: UIViewController) {
if let index = self.controllers.indexOf(viewController) {
// Do something with index
}
}

Resources