I have made a tabbar in storyboard with 4 bar items, I connected all of them to other view controllers by rightclick dragging and setting viewcontroller segue. Now for the second button i want to show an imagepicker instead of a viewcontroller. When i delete the second segue from storyboard in UITabBarController, my 4th bar item disappears.
This is my tabview controller
class BaseTabBarController: UITabBarController, UITabBarControllerDelegate {
let arrayOfImageNameForUnselectedState = ["home", "explore", "addIcon", "notification", "accountIcon"]
let arrayOfImageNameForSelectedState = ["homeFilled", "exploreFilled", "addIcon", "notificaitonFilled", "accountIcon"]
override func viewDidLoad() {
super.viewDidLoad()
self.delegate = self
if let count = self.tabBar.items?.count {
for i in 0..<count {
let imageNameForSelectedState = arrayOfImageNameForSelectedState[i]
let imageNameForUnselectedState = arrayOfImageNameForUnselectedState[i]
self.tabBar.items?[i].selectedImage = UIImage(named: imageNameForSelectedState)?.withRenderingMode(.alwaysOriginal)
self.tabBar.items?[i].image = UIImage(named: imageNameForUnselectedState)?.withRenderingMode(.alwaysOriginal)
}
}
}
override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
if tabBar.items?.index(of: item) ?? 0 == 2 {
//Clicked add tab, cancel segue and show imagepicker
} else {
selectedTabindex = tabBar.items?.index(of: item) ?? 0
}
}
}
How do I show image picker on 2nd bar button click
Do not Delete Second segue from storyboard put dummy view controller to show tab button inside tabbar. Implement UITabBarController controller's delegate method in subclass of UITabBarController and return false in shouldSelect method for second viewcontroller and present ImagePicker View for there.
Code:
class BaseTabBarController : UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
self.delegate = self
}
override var prefersStatusBarHidden: Bool {
return false
}
}
extension BaseTabBarController : UITabBarControllerDelegate {
func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
if self.viewControllers?.index(of:viewController) == 1 {
// TO Do code for Image Picker and Present it
return false
} else {
return true
}
}
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
}
}
Related
I have a tabbar controller. When the user clicks on one of the tab bar buttons, I need to update a value in the UIPageViewController that is in the target view controller.
I am trying to use a delegate to inform a UIPageViewController which tab bar button was clicked:
protocol PlanTypeDelegate {
func setIntro(thisFlow planType: UITabBarItem)
}
class NewTabBarController: UITabBarController {
var planTypeDelegate : PlanTypeDelegate?
override func viewDidLoad() {
super.viewDidLoad()
// create and handle tab bar button actions
}
override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
planTypeDelegate?.setIntro(thisFlow: item)
}
In my UIPageController I have the following:
class IntroPageController: UIPageViewController {
override func viewDidLoad() {
super.viewDidLoad()
guard let tabbar = self.parent as? NewTabBarController() else { return }
tabbar.delegate = self
}
}
extension IntroPageController : PlanTypeDelegate {
func setIntro(thisFlow planType: UITabBarItem) {
print("this item:\(planType)")
}
}
Instead I get this error message:
I am new to passing data between VCs so I have no idea how to go about handling this scenario.
EDIT
Same error after update
You can Achieve it like this.. without Delegate ... write setIntro method in IntroPageController i hope it will solve your Issue
class NewTabBarController: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
self.delegate = self
}
}
func tabBarController(_ tabBarController: UITabBarController,
shouldSelect viewController: UIViewController) -> Bool{
if let controller = viewController as? IntroPageController {
controller.setIntro(thisFlow: tabBarController.tabBarItem)
}
return true
}
You can also achieve it through Protocol for that write... All controllers who confirm PlanTypeDelegate can perform action against this method
func tabBarController(_ tabBarController: UITabBarController,
shouldSelect viewController: UIViewController) -> Bool{
if let navController = viewController as? UINavigationController {
if let myViewController = navController.topViewController , let homeController = myViewController as? PlanTypeDelegate {
homeController.setIntro(thisFlow: tabBarController.tabBarItem)
}
} else if let controller = viewController as? PlanTypeDelegate {
controller.setIntro(thisFlow: tabBarController.tabBarItem)
}
return true
}
I write the following code inside the function and call that into viewWillAppear method.
I want to disable to Tabbar Bottom items access.
Here TabarVC() is TabBarView controller class name.
let tabbar = TabarVC()
tabbar.tabBar.isUserInteractionEnabled = false
class OneViewController: UIViewController ,UITabBarControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
self.tabBarController?.delegate = self
}
func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
if viewController.isKind(of: twoViewController.self as AnyClass) {
return true
}
if viewController.isKind(of: threeViewController.self as AnyClass) {
return false
}
}
}
I have an UITabBarController and sometimes in didSelectItem delegate I need to pause the event and present a popup. If user confirmed the event resumes and if not, event will be canceled. Here's my code:
class YC_TabBarController: UITabBarController {
var prevIndex: Int!
var exitAction: (()->Bool)?
override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
self.prevIndex = self.selectedIndex
if self.prevIndex == 2 {
guard self.exitAction != nil else {return}
//pause
let isExitAccepted: Bool = self.exitAction!()
//if true -> resume
//if false -> prevent from switching tab
}
}
}
How can I do that? Please Help
You should confirm to UITabBarControllerDelegate in first view controller and return false if the desired view controller is selected in shouldSelect viewController. Then you should show your popup view. In popup view ok/confirm button you can change selected view controller of the self.tabBarController
class ViewController: UIViewController,UITabBarControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
self.tabBarController?.delegate = self
}
func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
if viewController is SecondViewController {
//show alert
return false
} else {
return true
}
}
func popUpOkAction(_ sender:UIButton) {
if let secVC = self.tabBarController?.viewControllers?.first(where: { $0 is SecondViewController }) {
self.tabBarController?.selectedViewController = secVC
}
}
}
If you want to perform this from multiple view controllers rather than
firstViewController you can confirm to UITabBarControllerDelegate in
YC_TabBarController itself.
This question has been asked before and has been answered, my question is not unique but there must be something missing. I'm simply trying to check if user logged in to app before as his data stored in UserDefaults but it doesn't work for me, this is the class of my TabBarViewController
class TabViewController: UITabBarController, UITabBarControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
self.delegate = self
}
// UITabBarDelegate
override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
print("Selected item")
}
// UITabBarControllerDelegate
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
if(viewController is MessagesViewController) {
print("trueee")
if(UserStorage.id == "") {
Toast.toast(messsage: "not loggoed user", view: self.view)
}
} else {
print("faaaaaaaalse")
}
print("Selected view controller")
}
}
i want to check if user open MessageViewController then if user is logged in to print something but it always print faaaaaaaalse
note: Toast.toast() is a function i created to show toast
and UserStorage.id returns user id stored in USerDefaults
this is image which shows my structure:
what should I do ?
Just your tab bar’s root controllers are 2 navigaton controllers, not MessageViewController. Firstly with tabBarController you have to find navigationController which contains your MessageViewController than in this navigation find the needed ViewController.
So I have the solution for you:
import UIKit
class TabbarController: UITabBarController, UITabBarControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
self.delegate = self
// for tab bar initialization
if let viewControllers = self.viewControllers,
viewControllers.count >= 1,
// the index of viewController is 0 here, but if your tab bar's started controller is not 0 you can set yours
let navigationController = viewControllers[0] as? UINavigationController {
for controller in navigationController.viewControllers {
if let messagesViewController = controller as? MessagesViewController {
doWithMessagesViewControllerWhatYouWant(_viewController: messagesViewController)
}
}
}
}
// UITabBarControllerDelegate
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
if let navigationController = viewController as? UINavigationController{
for controller in navigationController.viewControllers {
if let messagesViewController = controller as? MessagesViewController {
doWithMessagesViewControllerWhatYouWant(_viewController: messagesViewController)
}
}
}
}
private func doWithMessagesViewControllerWhatYouWant(_viewController: MessagesViewController) {
print("do some operations with messagesViewController")
if(UserStorage.id == "") {
Toast.toast(messsage: "not loggoed user", view: self.view)
}
}
}
Swift: I have UITabBarController, with 8 tabs. When user select any tab including more tab, I want reset content of selected tab by Popping to rootView controller?
How could this be done?
I tried to reset navigation controllers in below methods, It works for tabs which are visible at bottom but it doesn't work for More tab.
tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController)
override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem)
A clean way to do this:
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
let index = tabBarController.selectedIndex
if index == NSNotFound || index > 4 {
tabBarController.moreNavigationController.popToRootViewController(animated: false)
return
}
let navController = tabBarController.viewControllers?[tabBarController.selectedIndex] as? UINavigationController
navController?.popToRootViewController(animated: false)
}
Create a custom class for your UITabViewContoller, set a delegate and put there that piece of code.
You can create a UITabBarController class for your tabBar and in that class ovveride the tabBar didSelect method from their on select of any tab you can popViewController
class TabBarViewController: UITabBarController {
override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
let navigationController1 = self.viewControllers![0] as? UINavigationController
navigationController1!.popViewController(animated: false)
let navigationController2 = self.viewControllers![1] as? UINavigationController
navigationController2!.popToRootViewController(animated: false)
let navigationController3 = self.viewControllers![2] as? UINavigationController
navigationController3!.popToRootViewController(animated: false)
let navigationController4 = self.viewControllers![3] as? UINavigationController
navigationController4!.popToRootViewController(animated: false)
}
}
Use viewControllers property of UITabbarController. viewControlers is an array of UIViewController for UITabbarController. Exchange/Move position of view controllers upon tabbar(controller) selection.
Use tabbar(controller)'s delegate method to hanlde these operations, like:
Swift 3
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
if var viewcontrollers = tabBarController.viewControllers {
viewcontrollers.remove(at: tabBarController.selectedIndex)
viewcontrollers.insert(viewController, at: 0)
tabBarController.viewControllers = viewControllers
}
}
You can also use this delegate method, if you have an access to tabbarController where you have implemented.
func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
// Write a similar code to exchange/move view controllers using tabbarController instance.
}
This worked for me.
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
guard let navigationController = tabBarController.viewControllers?[tabBarController.selectedIndex] as? UINavigationController else {
return
}
navigationController.popToRootViewController(animated: false)
}
To fully support More, create a custom class like below:
class Main_TabBarController: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
self.customizableViewControllers = [] //remove Edit from More (OPTIONAL)
}
override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
if let index = tabBar.items?.firstIndex(of: item) {
if let count = viewControllers?.count, count > 5, index == 4 {
DispatchQueue.main.async {
self.moreNavigationController.popToRootViewController(animated: false)
}
} else if let vcs = viewControllers, let vc = vcs[index] as? UINavigationController {
DispatchQueue.main.async {
vc.popToRootViewController(animated: false)
}
}
}
}
}