How can I prevent a tab from being clicked, depending on conditions ? I tried several things and I probably missed some basics.
I'm having an UITabBarCustomController implementing UITabBarController. In the viewDidLoad, depending on a condition, i force the selectedIndex to 1, which works.
Nevertheless, i'm not able to prevent users leaving this tab. I tried to set a UITabBarControllerDelegate on the other ViewController's linked with my UITabBar, where I implemented - (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController, and finally i also tried to implement this delegate and method on my custom UITabBarCustomController. But in both cases, when i click on another tab, nothing happens and users are able to access the tab (NSLog in those methods don't show in debug).
Any ideas ? thanks.
// Edit : Test code in delegate method :
- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController
{
NSLog(#"test");
return NO;
}
This is how you can stop/prevent Tabbar items to switch your tab on tabbar item click
For Swift 3.0
Make sure you have implemented UITabBarControllerDelegate and set UITabbarController's delegate to self
then override this delegate in your controller
func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
if viewController == tabBarController.viewControllers?[2] {
return false
} else {
return true
}
}
Related
I have encountered a very awkward autolayout issue. I have a Navigation controller, i have set its rootviewcontroller as tabbarview controller for some purpose. See Image bellow:
In above image you can see there are 6 viewcontroller connected with tabbarviewcontroller.
In 3rd 4th 5th and 6th viewcontroller a white view is added and autolayout as given below:
Now, after run when i select tab 3 or 4, the added view shows perfectly as i wanted and according to autolayout it should be show as it is showing. i.e given below:
Now when I select "more" then it showing a tableviewcontroller as it should be according to its default behaviour, is given below:
Here is the problem occurred, now if you select any item from the list and go to respected view controller, the white view added goes down from navigation bar. I don't understand why this happening. please see in the pic:
Whole day I had tried to fix this but nothing happens, some how got one solution but it was not what I needed here. i.e see Image below:
If uncheck "Under Top Bars" for that view controller then its works fine, but it affects the navigation bar, which I not wanted here. please see the image:
Can somebody here who had faced the similar kind of problem and found a perfect solution and I'm looking for help.
Note: No class have been taken in any view controller, all are in storyboard.
Thanks in advance.
This is the problem there is a two navigation bar....you can track view hierarchy.....can you explain me what you want ?
Took a UiTbaBarControllerClass for my tabbarcontroller and in that that controller i set delegate self and follow my code, now its working as i wanted. very thanks to #KKRocks
Code:
#import "TabBarController.h"
#interface TabBarController ()<UITabBarControllerDelegate>
#end
#implementation TabBarController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.delegate = self;
}
#pragma mark UITabBarController Delegate
- (void)tabBarController:(UITabBarController *)tabBarController
didSelectViewController:(UIViewController *)viewController
{
NSLog(#"controller class: %#", NSStringFromClass([viewController class]));
NSLog(#"controller title: %#", viewController.title);
if ([viewController.title isEqual:#"More"]) {
[self.navigationController setNavigationBarHidden: YES animated: NO];
}
}
And in Swift:
class TabBarController: UITabBarController, UITabBarControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.delegate = self
}
// MARK: UITabBarController Delegate
func tabBarController(_ tabBarController: UITabBarController, didSelectViewController viewController: UIViewController) {
print("controller class: \(String(describing: viewController.self))")
print("controller title: \(String(describing: viewController.title))")
if viewController.title?.isEqual("More") {
navigationController?.setNavigationBarHidden(true, animated: false)
}
}
}
Now it working very fine. :)
I'd like to add an action sheet that appears when tab bar center item is clicked. like in this example:
this is how it shows when center item is clicked
i have added the tab bar from storyboard and its working fine.
the hard part of it is how to keep the previous view and overlay the action sheet.
thanks in advance.
use this delegate function to intercept tab selection
for swift 3
func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
if self.tabBarController.customizableViewControllers.index(of: viewController) == 2 {
//display action sheet
return false
}
return true
}
for objective c
- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController {
//same logic above
}
You could simply create an empty view controller, and present the action sheet in viewDidAppear. But you have to think of what to do (e.g. which view controller to display)
after the user chose an option
if the user cancels the action
I Want to call my own method, i.e. myMethod() when same tab bar is selected which is already selected.
I had tried to call didSelectMethod() but it is not called in my ViewController class.
Please help me in this,
Thank you
Jagveer Rana
Where you own your tabBarController instance there you set delegate
tabBarController.delegate= self; // It is must to set delegate
add the below delegate method
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
{
if ([viewController respondsToSelector:#selector(myMethod)]) {
[viewController performSelector:#selector(myMethod)];
}
}
It sounds like your ViewController class is not the delegate for your UITabBarController, otherwise tabBarController:didSelectViewController: would be called.
Make sure your delegate is linked up properly.
If that's not the problem, then there are a few other StackOverflow questions asking the same thing:
Tab bar, reload every time tab is pressed
Detect a re-tab on selected UITabbarItem
I have 3 tabs in my UITabbarController, that I created in my Appdelegate.
When I open the app, I have made the selected tabbarItem the third tabbarItem.
The user can only select the UITabBarItem at Index 0, when he is logged in.
I tried every thing to restrict the user from going to TabBarItem_0 when he is at TabBarItem_2.
But nothing worked. I used
- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController
{
}
But it's not working as I desired. I checked the stackoverflow and found almost the same question, where I found this delegate. But this is not working for me as desired. I googled, but couldn't find any solution other than stackoverflows links, which didn't help this time.
On the click of that disabled TabBar Item, I have to show a pop up. How can I implement that, too?
Try something like this,
- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController;
{
if (tabBarController.selectedIndex == 0) {
if(isUserLoggedIn)
return YES;
else
return NO;
}
return YES;
}
If this does not work then,
Add this after you create the bar bar in app delegate,
[[[[self.tabBarController tabBar]items]objectAtIndex:0]setEnabled:FALSE];
once you log in enable it again
[[[[self.tabBarController tabBar]items]objectAtIndex:0]setEnabled:TRUE];
Quick hack that i used to present a popup on top of the current view when tapped on a tab bar item.
In your TabBarViewController class, implement the UITabBarControllerDelegate and remember to set self.delegate = self.
After that
func tabBarController(tabBarController: UITabBarController, shouldSelectViewController viewController: UIViewController) -> Bool {
if viewController.title == "Unique_title" //set an unique title for the view controller in storyboard or the view controller class.
{
performSegueWithIdentifier("YourModalViewIdentifier", sender: nil)
return false
} else {
return true
}
}
That should help you display a modal view when tap is received on the uitabbaritem. I know using title as an unique identifier is bad practice, but just a quick solution to achieve what you want.
Hope that helps.
You can do this in your code
- (void)viewDidLoad {
...
[self checkLogin];
...
}
- (void)checkLogin {
if (!loggedIn) {
[[[[self.tabBarController tabBar]items]objectAtIndex:0]setEnabled:NO];
} else {
[[[[self.tabBarController tabBar]items]objectAtIndex:0]setEnabled:YES];
}
}
- (void)tapLogin {
// Do the login action
}
- (void)processLoginResult {
// Process the result of the login action
// If the result is success, set 'loggedIn = YES'
// Otherwise, set 'loggedIn = NO'
...
[self checkLogin];
...
}
If you want to do it with the Storyboard, simply selected the TabBarItem in the destination view controller scene and uncheck the Enabled box.
This is what I did in Swift 2.1:
self.tabBarController!.tabBar.items![0].enabled = false
Here is how you disable a tabbar item in Swift 3 and 4
tabBarController.tabBar.items![0].isEnabled = false
I have a Tab Bar Controller with four navigation controllers added to it. The navigation controllers appear as Tab Bar Items in the Tab Bar Controller. Now I want to add a fifth button to the tab bar, that does not open another view, but triggers some custom code. I want to display an overlaying "share menu" when clicking that Tab Bar Item regardless on which of the four pages the user is. How can I do that?
I can suggest to add dummy UIViewController to the last index and handle UITabBarControllerDelegate
- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController {
if ([viewController == ...your dummy view controller...]) {
//Your custom action
return NO;
}
return YES;
}
Krivoblotsky has given the right answer! I'd like to elaborate a little more for anyone who is confused because for the full implementation there are a couple more moving parts. Let's say you have the app below. As it is when you click the home or profile icon the respective view will display. Let's say instead of the profile view to display, you want to add your custom transition / behavior.
To do this:
1. Given ProfileViewController class, you want include the UITabBarControllerDelegate in your ProfileViewController
#interface ProfileViewController : ViewController <UITabBarControllerDelegate> #end
2. Access your tabBarcontroller's delegate and set this as yourself in your ProfileViewController.m's viewDidLoad
self.tabBarController.delegate = self;
Essentially what this does is say hey, you know the tabBarController's delegate? (The guy that handles events) I know a guy and let this guy (self) handle those events instead. Like in English, you DELEGATE work to other people (you are the delegating object). The thing that handles the work, is the DELEGATE.
3. Implement the custom needed behavior
-(BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:
if ([viewController isKindOfClass:[ProfileViewController class]]){
NSLog(#"It's a profile");
return NO };
};
else{ return YES; }
The NO return says, when ProfileViewController is selected, do not do default behavior and display it's view.
Excellent explanation of delegates
In Storyboard, add a UIVIewController and connect it to the tab button you want to perform your custom action.
Give that UIViewController a unique title. e.g. "for custom action". It really doesn't matter, as nobody will ever see that title. It is just for you to use in the code below to identify that tab was tapped.
Create the class below and assign it to your UITabBarController in Storyboard
class TabBarController: UITabBarController, UITabBarControllerDelegate {
override func viewDidLoad() {
delegate = self
}
func tabBarController(tabBarController: UITabBarController, shouldSelectViewController viewController: UIViewController) -> Bool {
if viewController.title == "for custom action" {
//do your custom actions
return false
}
return true
}
}
You should simply implement the following UITabBarDelegate method:
- (void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item;