How can I prevent an unwind segue from UITabBar? - ios

I have a Show segue that is embedded in a UITabBarController. I want to prevent an unwind segue when I tap the currently selected tab unless a certain condition is met. I've tried using shouldPerformSegueWithIdentifier and canPerformUnwindSegueAction but neither appear to be triggered when unwinding in this way.

Not sure what you mean by unwind segue on a tab bar, but if you want to prevent a tab change, there is a delegate function on UITabBarController for that purpose.
Add the protocol to your tab bar class.
#interface YourTabbarViewController () <UITabBarControllerDelegate>
#end
Assign the delegate, then later implement the function.
#implementation YourTabbarViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.delegate = self;
}
- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController {
if (preventTabChange)
return NO;
return YES;
}
UPDATE
OK, assuming you have set up relevant parts as on this picture, and you want to prevent the unwind from B to A if certain conditions are met. My solution as described above will work.
As you will get a query/notification whenever the Navigation Controller is about to become active, you could create your own sub-class of that to hold whatever information you need to decide if it should be allowed to show or unwind from a sub-view controller. In that case your prevention could look like this (expanding the shouldSelectViewController above):
- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController {
if ([viewController isKindOfClass:[YourNavigationController class]]) {
if ([(YourNavigationController *)viewController preventUnwind])
return NO;
}
return YES;
}
Note that I purposely chose preventUnwind as a flag in your custom class to say what to do. This will default to NO when you move to the view controller, and thus allowing that.
Don't forget to set YourTabbarViewController as the class for the Tabbar View Controller and YourNavigationController as the Navigation Controller in the picture.

Related

How Can I handle an UITabBarItem clicked twice consecutive and dismiss segues?

My UITabBarController caching everything about before selected item, It's nice but I want to dismiss each segue presented by me When I have clicked displayed view's item, twice consecutive same page.
How and What I need to do to provide this case? Detailed answer for solution It would be great.
Use tabbarControler delegate method
- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController
{
if (alreadyPushed){
return false
}
return true
}

Use prepareForSegue:Sender when switching VC in UITabBarController

I have googled far and wide, but everything is extremely confusing. I need it so when the tab bar gets switched to a different view controller, is there a method that gets called when the view controllers are about to switch, get the destination controller and set some variables to add some annotations to a MKMapView. How can I do this?
There are many options, but one of them is to implement the UITabBarControllerDelegate protocol and then set the class that implements it as the delegate of your UITabBarController. The delegate receives a message - tabBarController:didSelectViewController:
In that method you can implement the behavior you desire by looking at the last view controller and the next one. To get access to those view controllers from your delegate, you may need to add them as weak properties to your delegate class. You can also access all of your UITabBarController's sub view controllers through its viewControllers property which is an array of view controllers.
After some experimentation with the delegate methods, I was able to find an answer.
I used the - (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController method.
This feels like a fairly decent replacement because you can get each controller easily.
Warning: This method should not be used to handle large blocks of code, but to set up a view controller to run large blocks of code.
A test implementation:
- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController
{
FirstViewController *currentController = (FirstViewController *)[tabBarController selectedViewController];
SecondViewController *destinationController = (SecondViewController *)viewController;
// If you want, do some code on these here. For more precision, read on.
return YES;
}
This can be used with logic to determine whether you should execute some specific code: EX:
if ([[tabBarController selectedViewController] class] == [FirstViewController class]) {
if ([viewController class] == [SecondViewController class]) {
// It is going from first to second. Do some code here.
}
}
Also, you have to have set the delegate
TabBarController .h
#interface TabBarController : UITabBarController<UITabBarControllerDelegate>
...
TabBarController .m
...
- (void)viewDidLoad
{
self.delegate = self;
}
...

want to call myMethod() when selecting same tab bar in IOS

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

Custom action when clicking on UITabBarController

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;

Impose a condition needing to be satisfied before user changes to another tab

I have situation where I need to make sure that user has completed certain steps before they move to another tab inside UITabBarController. So if the user is in middle of something and taps on another tab, I would like to show a UIAlertView saying "you must complete blah blah blah before you go to another tab."
Is it possible to to check this condition and cancel moving to another view controller?
Sure you can. I suppose you have your tabbar controller in the AppDelegate class. If so, set the AppDelegate to be its delegate. Then implement the following method
- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController {
// place all the checks here
EditingViewController *editingController = //link to controller where editing is being made.
if (editingController && editingController.isEditing) {
//UIAlertView
return NO;
}
return YES;
}
At a guess you could try catching the view on it's way out and changing the selected index on the tab bar controller to be the view you wish to keep them on:
- (void)viewWillDisappear:(BOOL)animated {
self.tabBarController.selectedIndex = 0;
}
You might find that's a bit jerky though depending on the order of events, a quick google has found that if you can make your view controller a UITabBarControllerDelegate then you can implement:
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
Which would allow you to catch them earlier. You might find it simplest to implement this in your App Delegate and have it know (or check) if it should allow the change away.

Resources