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) }
}
Related
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 facing a problem. When I want to change the View for a Tab View Controller, my application gives a black screen.
And here is my code to change view:
let homeViewController = self.storyboard?.instantiateViewController(identifier: Constants.Storyboard.homeViewController) as? HomeViewController
self.view.window?.rootViewController = homeViewController
self.view.window?.makeKeyAndVisible()
Constants.swift:
import Foundation
struct Constants {
struct Storyboard {
static let homeViewController = "homeVC"
}
}
homeVC is the first View of TabBarController, with the Label.
This is my way. I am not using storyboard by the way. I am using xib.
let dashboardVc = DashboardTabController()
self.window!.rootViewController = dashboardVc
self.window!.makeKeyAndVisible()
self.window?.overrideUserInterfaceStyle = .light
and then in dashboardTabController type this one.
import UIKit
class DashboardTabController: UITabBarController {
#IBOutlet weak var dashboardTabBar: UITabBar!
override func viewDidLoad() {
super.viewDidLoad()
let firstViewController = HomeViewController()
firstViewController.tabBarItem = UITabBarItem(title: "", image: UIImage(named: "ic_home_24px"), selectedImage: UIImage(named: "ic_home_24px"))
let secondViewController = AddContactViewController()
secondViewController.tabBarItem = UITabBarItem(title: "", image: UIImage(named: "ic_group_add_24px"), selectedImage: UIImage(named: "ic_group_add_24px"))
let tabBarList = [firstViewController, secondViewController]
viewControllers = tabBarList
}
}
don't forget in DashBoardTabController xib, implement the UITabBar in bottom. Hopefully it's helpful. Just mention me if you need more help on executing this.
I have implemented a menuViewVontroller for navigation drawer that works fine. I am able to render the view controllers on their respective menu buttons. I have one ViewController that loads up first and then I display other view controllers from the navigation menu i.e. Home menu displays the homeViewVontroller etc. as you can see in the screen shots.
But I also want my app to show the homeControllerView when the viewController loads. It is currently rendering an empty screen as the view controller is empty. When I write the below code in viewDidLoad() method, I am not getting the navigation drawer, just the homeViewController gets displayed (as shown in the picture below).
let view = UIView()
let controller = storyboard!.instantiateViewController(withIdentifier: "SliderController")
addChild(controller)
view.frame = self.view.bounds
self.view.addSubview(controller.view)
self.topView = view
What can I do to render both the homeViewController and the menuViewController in the same screen.
EDIT: My code when the user presses the menu item
#IBAction func didTapMenuButton(_ sender: UIBarButtonItem) {
guard let menuViewController = storyboard?.instantiateViewController(withIdentifier: "MenuViewController") as? MenuViewController else { return }
menuViewController.didTapMenuType = {
menuType in
self.transitionToNew(menuType)
}
menuViewController.modalPresentationStyle = .overCurrentContext
menuViewController.transitioningDelegate = self
present(menuViewController, animated: true)
}
func transitionToNew(_ menuType: MenuType) {
let title = String(describing: menuType).capitalized
self.title = title
topView?.removeFromSuperview()
switch menuType {
case .promotion:
let view = UIView()
view.backgroundColor = .yellow
view.frame = self.view.bounds
self.view.addSubview(view)
self.topView = view
case .billPayment:
let view = UIView()
view.backgroundColor = .blue
view.frame = self.view.bounds
self.view.addSubview(view)
self.topView = view
default:
break
}
}
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
}
Intended Outcome
A generic private method for creating tabbbar icons in a custom tabbar controller. Should successfully paint the tabbar icons for each indicated controller.
Result
Fails with
Cannot Call Value of Non-Function Type 'UICollectionView'
Failing (Generic) Code:
private func createNavController(imageName: String, _ controllerName: UICollectionViewController) -> UINavigationController {
let layout = UICollectionViewFlowLayout()
Thrown Here-> let viewController = controllerName(collectionViewLayout: layout)
let navController = UINavigationController(rootViewController: viewController)
navController.tabBarItem.image = UIImage(named: imageName)
return navController
}
Working (non-generic) Code
let userLayout = UICollectionViewFlowLayout()
let userController = UserController(collectionViewLayout: userLayout)
let navController = UINavigationController(rootViewController: userController)
navController.tabBarItem.image = UIImage(named: "loc-map-route")
Related
class UserController : UICollectionViewController, UICollectionViewDelegateFlowLayout
{
override func viewDidLoad() {
super.viewDidLoad()
collectionView?.backgroundColor = UIColor.green
}
}
Environment
ios 10 swift 3 xcode 8
Thanks.
In your definition of createNavController your parameter controllerName is of type UICollectionViewController and that is not a function type so you cannot call it as a function, i.e. controllerName(...).
If you replace
let viewController = controllerName(collectionViewLayout: layout)
with
let viewController = UserController(collectionViewLayout: layout)
from your working code, it compiles fine. Also, you don't need the controllerName parameter anymore. I don't quite understand what this is for anyway. Did you want to be able to specify the controller type? Then you could do it like dan suggests (although this code requires a UICollectionViewController because you would be using init(collectionViewLayout:)).
You could also pass an instance of the view controller you want embedded in the navigation controller like this:
private func createNavController(imageName: String, rootViewController: UIViewController) -> UINavigationController
{
let navController = UINavigationController(rootViewController: rootViewController)
navController.tabBarItem.image = UIImage(named: imageName)
return navController
}
and call it like this:
let navController = createNavController(
imageName: "loc-map-route",
rootViewController: UserController(collectionViewLayout: UICollectionViewFlowLayout()))
This would indeed not require a UICollectionViewController because UINavigationController.init(rootViewController:) takes a UIViewController. It all depends on what you want to achieve.
Do you want something like this?
private func createNavController<T: UICollectionViewController>(imageName: String, _ controllerName: T.Type) -> UINavigationController {
let layout = UICollectionViewFlowLayout()
let viewController = controllerName.init(collectionViewLayout: layout)
let navController = UINavigationController(rootViewController: viewController)
navController.tabBarItem.image = UIImage(named: imageName)
return navController
}
Then you can do: let nav = createNavController(imageName: "loc-map-route", UserCollectionController.self) and nav will have a UserCollectionController as its root.
I think that controllerName is an instance of UICollectionViewController, so it is an already initialized UICollectionViewController. It is not the name of the UICollectionViewController subclass. So if you just want to set the collectionViewLayout of that UICollectionViewController, I'd do:
private func createNavController(imageName: String, _ controllerName: UICollectionViewController) -> UINavigationController
{
let layout = UICollectionViewFlowLayout()
let viewController = controllerName.collectionViewLayout = layout
let navController = UINavigationController(rootViewController: viewController)
navController.tabBarItem.image = UIImage(named: imageName)
return navController
}
The you would call it like this:
let navController = createNavController(imageName: "my_image", myCreatedUserController)