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)
}
}
Related
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)
I have a tab bar controller that shows 5 tabs. It shows perfectly in iOS 12 or earlier as shown here
.
But if I run the same in iOS 13, the design is totally messed up
.
It totally loses the scroll view insets, and it is also not adjusting the bottom insets of my menus table view. some of the menus are hidden in the bottom. they are not scrolling up. and this is the code that I'm using in UITabBarController
override func viewDidLoad() {
super.viewDidLoad()
delegate = self
guard let user = user else {
appDelegate.instituteSelectionView()
return
}
var dashBoard: UINavigationController
var menus: UINavigationController? = nil
// Creating all the view controllers for tabs.
if user.role.caseInsensitiveCompare("student") == .orderedSame {
let dashBoardVC = mainStoryBoard.instantiateViewController(withIdentifier: "DashboardVC") as! DashboardVC
dashBoardVC.menus = ContentProvider.getMenus()
dashBoardVC.school = user.school
dashBoard = UINavigationController(rootViewController: dashBoardVC)
dashBoard.navigationBar.prefersLargeTitles = true
} else {
let dashBoardVC = mainStoryBoard.instantiateViewController(withIdentifier: "DashboardWidgetsTableViewController") as! DashboardWidgetsTableViewController
dashBoardVC.user = user
dashBoardVC.title = "Dashboard"
dashBoard = UINavigationController(rootViewController: dashBoardVC)
let menusVC = mainStoryBoard.instantiateViewController(withIdentifier: "MenusTableViewController") as! MenusTableViewController
menusVC.setMenus(ContentProvider.getMenusForStaff())
menus = UINavigationController(rootViewController: menusVC)
}
dashBoard.tabBarItem = UITabBarItem(title: "Dashboard", image: #imageLiteral(resourceName: "dashboard"), tag: 0)
if menus != nil {
menus?.navigationBar.prefersLargeTitles = true
menus?.tabBarItem = UITabBarItem(title: "Menus", image: #imageLiteral(resourceName: "menu-1"), tag: 1)
}
let notificationVC = mainStoryBoard.instantiateViewController(withIdentifier: "NotificationsTabTableViewController") as! NotificationsTabTableViewController
notificationVC.user = user
let notification = UINavigationController(rootViewController: notificationVC)
notification.tabBarItem = UITabBarItem(title: "Notifications", image: #imageLiteral(resourceName: "bell"), tag: 3)
notification.tabBarItem.badgeValue = user.badge > 0 ? String(user.badge) : nil
notification.navigationBar.prefersLargeTitles = true
let settingsVC = mainStoryBoard.instantiateViewController(withIdentifier: "SettingsTabTableViewController") as! SettingsTabTableViewController
settingsVC.user = user
let settings = UINavigationController(rootViewController: settingsVC)
settings.tabBarItem = UITabBarItem(title: "Settings", image: #imageLiteral(resourceName: "settings"), tag: 4)
settings.navigationBar.prefersLargeTitles = true
let accountsVC = mainStoryBoard.instantiateViewController(withIdentifier: "AccountsTableViewController") as! AccountsTableViewController
let accounts = UINavigationController(rootViewController: accountsVC)
accounts.tabBarItem = UITabBarItem(title: "Accounts", image: #imageLiteral(resourceName: "user_group_man_man"), tag: 5)
accounts.navigationBar.prefersLargeTitles = true
mViewControllers = [dashBoard, notification, settings, accounts]
if menus != nil {
mViewControllers.insert(menus!, at: 1)
}
// Adding logo and profile button to navigation bar of each view controller.
for vc in mViewControllers {
if let nVC = vc as? UINavigationController, let vc = nVC.topViewController {
let logo = UIImageView(image: #imageLiteral(resourceName: "educare logo"))
logo.contentMode = .scaleAspectFill
logo.clipsToBounds = true
logo.widthAnchor.constraint(equalToConstant: 24).isActive = true
logo.heightAnchor.constraint(equalToConstant: 24).isActive = true
let profileButton = UIButton(type: .custom)
profileButton.widthAnchor.constraint(equalToConstant: 24).isActive = true
profileButton.heightAnchor.constraint(equalToConstant: 24).isActive = true
profileButton.imageView?.layer.cornerRadius = 12
if #available(iOS 13.0, *) {
let image = UIImage(systemName: "person.crop.circle")
profileButton.sd_setImage(with: URL(string: user.image), for: .normal, placeholderImage: image)
} else {
profileButton.sd_setImage(with: URL(string: user.image), for: .normal, placeholderImage: #imageLiteral(resourceName: "user_circle"))
}
profileButton.addTarget(self, action: #selector(openProfile), for: .touchUpInside)
let logoButtonItem = UIBarButtonItem(customView: logo)
let profileButtonItem = UIBarButtonItem(customView: profileButton)
vc.navigationItem.leftBarButtonItem = logoButtonItem
vc.navigationItem.rightBarButtonItems = [profileButtonItem]
}
}
setViewControllers(mViewControllers, animated: true)
}
Update: Actually the first view controller in the tab bar controller renders correctly but the rest of the view controllers have that ugly navigation bar.
I Solved the problem. turns out it was the transition animation (from the initial view controller to the main tab bar controller) that was causing the problem. So i changed the code from this
if animated {
UIView.transition(from: (window?.rootViewController?.view)!, to: viewController.view, duration: duration, options: animationOptions) { (completed) in
if completed {
self.window?.rootViewController = viewController
self.window?.makeKeyAndVisible()
}
}
} else {
self.window?.rootViewController = viewController
self.window?.makeKeyAndVisible()
}
to this
guard let window = UIApplication.shared.keyWindow else { return }
window.rootViewController = viewController
window.makeKeyAndVisible()
if animated {
UIView.transition(with: window, duration: duration, options: animationOptions, animations: {})
}
CNContactViewController navigation bar colour not appearing when i click Create New Contact option. See my screens for 1st time it's ok, but when i click Create New Contact i'm not getting navigation bar colour and not visible back button.
1st screen
2nd screen
In older versions
My code is
if #available(iOS 9.0, *) {
let store = CNContactStore()
let contact = CNMutableContact()
let homePhone = CNLabeledValue(label: CNLabelHome, value: CNPhoneNumber(stringValue : self.mobile ?? ""))
contact.phoneNumbers = [homePhone]
let controller = CNContactViewController(forUnknownContact : contact)
controller.contactStore = store
controller.delegate = self
if #available(iOS 10.0, *) {
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + Double(Int64(0.1 * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC), execute: {
//Set status bar background colour
let statusBar = UIApplication.shared.value(forKeyPath: "statusBarWindow.statusBar") as? UIView
statusBar?.backgroundColor = UIColor.red
//Set navigation bar subView background colour
for view in controller.navigationController?.navigationBar.subviews ?? [] {
view.tintColor = UIColor.white
view.backgroundColor = UIColor.red
}
})
}
navigationController?.pushViewController(controller, animated: true)
}
And one more is by default phone number: (913) 351-5518
I would suggest to display a CNConctactViewController within a UINavigationController in Popover Modal Presentation style, and add a few button to return to the main application. This implementation seams not trivial as reported by rumours over the net.
Let me share a few pieces of my code (swift 5).
The major class:
class MyViewController: UITableViewController, UIPopoverPresentationControllerDelegate {
var contactViewController = CNContactViewController()
...
#objc func dismissContactViewController() {
contactViewController.dismiss(animated: true, completion: nil)
}
}
The extension:
extension MyViewController: CNContactViewControllerDelegate {
func openCNContactViewController(willAppearWith: CNContact, type: ContactType) {
switch type {
case .forContact:
contactViewController = CNContactViewController(for: willAppearWith)
contactViewController.allowsEditing = false
break
case .forNewContact:
contactViewController = CNContactViewController(forNewContact: willAppearWith)
contactViewController.allowsEditing = true
break
case .forUnknowContact:
contactViewController = CNContactViewController(forUnknownContact: willAppearWith)
contactViewController.allowsEditing = true
break
}
contactViewController.allowsActions = true
contactViewController.contactStore = globalContactStore
contactViewController.hidesBottomBarWhenPushed = true
contactViewController.delegate = self
// define the button (or select a default one)
let button = UIButton(type: .custom)
button.setTitleColor(self.view.tintColor, for: .normal)
button.setTitle("My app name", for: .normal)
button.addTarget(self, action: #selector(dismissContactViewController), for: .touchUpInside)
let closeButton = UIBarButtonItem(customView: button)
closeButton.style = .plain
// add flexible space
let flexibleSpace = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.flexibleSpace, target: nil, action: nil)
// add to toolbar
contactViewController.setToolbarItems([flexibleSpace, closeButton, flexibleSpace], animated: false)
let navigationVC = UINavigationController(rootViewController: contactViewController)
// show toolbar
navigationVC.setToolbarHidden(false, animated: false)
// set navigation presentation style
navigationVC.modalPresentationStyle = .popover
// present view controller
self.present(navigationVC, animated: true, completion: nil)
}
The result
I want to create Tab bar with dynamic tab. I have created tab bar with dynamic tabs but when I navigate to details screen from my tab bar screen there is black space in that details view controller. please suggest me the right way to implement it. Here is my code.
func creatTabBarProgrammatically(bottomMenuArray:[Any]) {
DispatchQueue.main.async {
self.navigationController?.setNavigationBarHidden(true, animated: false)
let tabBarController = UITabBarController()
tabBarController.tabBar.backgroundImage = self.getImageWithColor(UIColor.white, size: CGSize(width: self.view.frame.size.width, height: 49))
tabBarController.hidesBottomBarWhenPushed = true
let firstViewController = self.storyboard?.instantiateViewController(withIdentifier: "HomeViewController") as! HomeViewController
let ordersViewController = self.storyboard?.instantiateViewController(withIdentifier: "OrdersViewController") as! OrdersViewController
let myProfileViewController = self.storyboard?.instantiateViewController(withIdentifier: "MyProfileViewController") as! MyProfileViewController
var controllers = [Any]()
controllers.append(firstViewController)
for i in 0 ..< bottomMenuArray.count{
if let dict = bottomMenuArray[i] as? [String:Any]{
if let name = dict["name"] as? String{
if name == "orders"{
controllers.append(ordersViewController)
}
else if name == "profile"{
controllers.append(myProfileViewController)
}else{
}
}
}
}
tabBarController.viewControllers = controllers as? [UIViewController]
// Setting Title selected image and unselected image to tab
for i in 0 ..< bottomMenuArray.count{
if let dict = bottomMenuArray[i] as? [String:Any]{
if let name = dict["name"] as? String{
if name == "orders"{
let tabBarItem :UITabBarItem = tabBarController.tabBar.items![i + 1]
tabBarItem.title = "Orders"
tabBarItem.selectedImage = UIImage(named: "tabordersselected")?.withRenderingMode(UIImageRenderingMode.alwaysOriginal)
tabBarItem.image = UIImage(named: "tabordersunselected")?.withRenderingMode(UIImageRenderingMode.alwaysOriginal)
}
else if name == "profile"{
let tabBarItem :UITabBarItem = tabBarController.tabBar.items![i + 1]
tabBarItem.title = "Profile"
tabBarItem.selectedImage = UIImage(named: "tabprofileselected")?.withRenderingMode(UIImageRenderingMode.alwaysOriginal)
tabBarItem.image = UIImage(named: "tabprofileunselected")?.withRenderingMode(UIImageRenderingMode.alwaysOriginal)
}else{
}
}
}
}
let tabBarItem1:UITabBarItem = tabBarController.tabBar.items![0]
tabBarItem1.title = "Home"
tabBarItem1.selectedImage = UIImage(named: "tabhomeselected")?.withRenderingMode(UIImageRenderingMode.alwaysOriginal)
tabBarItem1.image = UIImage(named: "tabhomeunseleted")?.withRenderingMode(UIImageRenderingMode.alwaysOriginal)
tabBarController.viewControllers = controllers.map { UINavigationController(rootViewController: $0 as! UIViewController)}
self.navigationController!.pushViewController(tabBarController, animated: false)
}
}
Try to force layout on controller you got bottom black bar
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.navigationController?.view.setNeedsLayout()
}
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!