How to get the RootViewController from a UITabBarItem - ios

Im not even sure if the title is correct but i do not understand how else to explain it so here it goes. I will show you in steps what i do so you will understand.
First off , i am using UITabBarController where i got three different items.
1) The app starts and it shows me the first Item which is a UITableView
2) I click on a cell and it pushes me to a detailed view of the cell.
3) I navigate from there to another TabBarItem
4) I navigate back to the first TabBarItem and it still shows me the view from step 3). I DONT want that i want it to show me the first view from step 1)
How can i achieve this?

You can implement UITabBarController delegate method:
- (void)tabBarController:(UITabBarController *)tabBarController
didSelectViewController:(UIViewController *)viewController
Which will let you know when a tab is selected.
You can then access the UIViewControllers of your UITabBar using if you don't have a reference to the UIViewControllers:
#property(nonatomic, copy) NSArray *viewControllers
From that grab the refence to the appropriate UIViewController (or UITableViewController) that you want to reset and call:
- (NSArray *)popToRootViewControllerAnimated:(BOOL)animated
On it's UINavigationController. Or create a public method for that call as call popToRootViewController that way.
EDIT:
Your AppDelegate should look like this:
#interface AppDelegate () <UITabBarControllerDelegate>
#end
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
UITabBarController *tabBarController = (UITabBarController *)self.window.rootViewController;
tabBarController.delegate = self;
return YES;
}
- (void)tabBarController:(UITabBarController *)tabBarController
didSelectViewController:(UIViewController *)viewController {
NSLog(#"was selecated");
}

Assuming you've set up your tab bar controller in the your AppDelegate, you want to make it your <UITabBarControllerDelegate>
And in your AppDelegate.m you want to implement this method like this:
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController {
if ([viewController isKindOfClass:[UINavigationController class]]) {
[(UINavigationController*)viewController popToRootViewControllerAnimated:YES];
}
}

Related

IOS: UITabBarControllerDelegate Methods from tableviewcontroller

I am trying to detect tapping of another tab from within a view controller embedded in a tabbarcontroller using one of the tabbarcontroller's delegate methods. However, I am confused about whether those methods can be in the individual view controllers or whether they have to be in the uitabbarcontroller class. I would like to have them in the view controllers where I have access to all the properties and local variables of those VCs rather than in the tabbarcontroller class.
I am also confused about how to set the delegate.
In a tableview controller embedded in the tabbarcontroller, I have declared the delegate protocol and then included the following code. However, the method is not firing. Is it okay to put this delegate method in a VC and if so, how and where should I set the delegate to get it to fire?
- (void)tabBarController:(UITabBarController *)tabBarController
didSelectViewController:(UIViewController *)viewController
{
NSLog(#"DIDSELECTVC FIRED");
NSLog(#"controller class: %#", NSStringFromClass([viewController class]));
NSLog(#"controller title: %#", viewController.title);
if (viewController == tabBarController.moreNavigationController)
{
tabBarController.moreNavigationController.delegate = self;
}
}
As said Toru Furuya said better way to implement UITabBarControllerDelegate is inside subclass of UITabBarController itself.
If you want to use certain inner view controller as delegate use tabBarController property:
- (void)viewDidLoad {
[super viewDidLoad];
self.tabBarController.delegate = self;
}
You can use either individual ViewController or UITabBarController itself for delegate as long as it conforms to UITabBarControllerDelegate protocol.
I think it is more common to use UITabBarController itself (or another dedicated class) to UITabBarControllerDelegate than child ViewControllers because you can set delegate only one. But if you want to use individual ViewController, I hope this code will help you.
#implementation MyTabBarController : UITabBarController
- (id)initWithCoder:(NSCoder *)aCoder{
self = [super initWithCoder:aCoder];
if (self) {
MyTableViewController *controller = [[MyTableViewController alloc] init];
controller.tabBarItem = ...
_delegate = controller; //Set individual ViewController to UITabBarControllerDelegate
[self setViewControllers:#[controller] animated:YES];
}
return self;
}
#end
MyTableViewController is:
#interface MyTableViewController : UITableViewController<UITabBarControllerDelegate>
#end
#implementation MyTableViewController
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController {
//Handle tap event of UITabBarController
}
#end

Dismiss all Detail Views when switching Tabs on TabBarController

My iOS app has:
TabBarController
NavigationController1
TableView1
ViewController1 (Details View)
NavigationController2
TableView2
ViewController2 (Details View)
Behavior:
When the app loads, I see the TableView1.
I select an Item in the table, and it takes me via Show (Push) segue the details view 1.
I switch to the second tab on the bottom, and see TableView2.
I select an item and it takes me to details view 2
I navigate back to first tab, and see details view 1
Desired:
When performing last step, I'd like to dismiss the details view and see the first TableView1, and when switching back to second tab, I want that one to be dismissed and to see the table view.
I've tried different combinations of dismissViewControllerAnimated and popToRootViewControllerAnimated but I just don't seem to figure it out.
MainTabBarController.h
#interface MainTabBarController : UITabBarController <UITabBarControllerDelegate>
MainTabBarController.m
- (void)viewDidLoad {
[super viewDidLoad];
self.delegate = self;
}
...
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController{
// NSLog Works fine, and displays information in the output
NSLog (#"%# %lu", tabBarController.selectedViewController.title, tabBarController.selectedIndex);
// None of the lines below achieve the desired result
[viewController.navigationController popToRootViewControllerAnimated:YES];
[viewController dismissViewControllerAnimated:YES completion:nil];
[tabBarController.navigationController popToRootViewControllerAnimated:YES];
[tabBarController dismissViewControllerAnimated:YES completion:nil];
}
One option is to make use of the UITabBarControllerDelegate. Listen for changes to the tab selection. Based on the new tab, get the tab's navigation controller and call its popToRootViewControllerAnimated: method.
Update based on the code added to the question:
The problem is with how you try to pop the view controllers. You want this:
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController{
// NSLog Works fine, and displays information in the output
NSLog (#"%# %lu", tabBarController.selectedViewController.title, tabBarController.selectedIndex);
// If the selected tab's root controller is a navigation controller
// pop to the top view controller in the tab's navigation stack
if ([viewController isKindOfClass:[UINavigationController class]]) {
UINavigationController *nav = (UINavigationController *)viewController;
[nav popToRootViewControllerAnimated:NO];
}
}
Here is a simple solution for this.
Try to implement the following methods of UIViewContorller
- (void)viewWillDisappear:(BOOL)animated; // Called when the view is dismissed, covered or otherwise hidden. Default does nothing
- (void)viewDidDisappear:(BOOL)animated; // Called after the view was dismissed, covered or otherwise hidden. Default does nothing
Go to your detail-1 view controller and implement the method - (void)viewWillDisappear:(BOOL)animated.
Do a pop for that controller.
Same you should do for the detail-2
Here is the code snippet that will help you.
In Appdelegate.m
#interface AppDelegate ()<UITabBarControllerDelegate>
#property(nonatomic, strong) MainTabBarController *rootTabBarController;
#end
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.rootTabBarController = [[MainTabBarController alloc]init];
self.rootTabBarController.delegate = self;
self.window.rootViewController = self.rootTabBarController;
[self.window makeKeyAndVisible];
}
TabBarController delegate implementation
-(void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController {
NSUInteger index = [self.rootTabBarController.viewControllers indexOfObject:viewController];
NSLog(#"Index : %lu", (unsigned long)index);
switch (index) {
case 0:
// pop other tab barcontrollers pushed or modal windows
[self.rootTabBarController flushViewControllerStackForIndex:1];
break;
case 1:
[self.rootTabBarController flushViewControllerStackForIndex:0];
break;
default:
break;
}
}
MainTabBarController.m
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[self setViewControllers:#[
[[UINavigationController alloc] initWithRootViewController:[[FirstViewController alloc]init]],
[[UINavigationController alloc] initWithRootViewController:[[SecondViewController alloc]init]]
] animated:YES];
}
-(void)flushViewControllerStackForIndex:(NSUInteger )index {
[[self.viewControllers objectAtIndex:index] popToRootViewControllerAnimated:NO];
}
Here is screenshot in sequence for the sample I ran.
Here is the Sample code.
That should solve your purpose & is the right approach.
Now you may need to fine tune your own logic in flushViewControllerStackForIndex to check if there is just only controller being pushed on stack or a combination of push & modal. So better try to navigate on the Stack & do-a-dismiss-if-a-modal or do-a-pop-if-a-push.
Hope that helps.
You can directly set the view controllers currently on the navigation stack. All you have to is directly set the viewControllers property of the navigation controllers when switch tabs in the tabbar controller.
Set NavigationController1.viewcontrollers = #[tableView1] when you switch to tab1

Navigation nested push caused by tabbar touch

- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController: (UIViewController *)viewController{
if (viewController == _personalNavViewCtrl) {
AppDelegate *delegate = (AppDelegate*)[UIApplication sharedApplication].delegate;
if (delegate.uid == nil) {//账户没有登陆过
if (_loginViewCtrl == nil) {
_loginViewCtrl = [[LoginViewCtrl alloc] init];
}
NSLog(#"_personalNavViewCtrl.ViewCtrl:%#",_personalNavViewCtrl.viewControllers);
if (_personalNavViewCtrl.topViewController != _loginViewCtrl) {
[_personalNavViewCtrl pushViewController:_loginViewCtrl animated:NO];
}
}
}
}
The above is the key code.the code have a UITabBarController, a UINavigationController is in it, its item is 4. When I touch item4, I want to push another UIViewController via some juge. So when the current item is 3, when i touch item4, it is ok. But when the current item is 4, i touch item4 again, I found this question. I find the UINavigationController viewControllers is only the rootViewController, the one I have pushed is dismissed.Another:the log tell me:1, nested push animation can result in corrupted navigation bar 2, Finishing up a navigation transition in an unexpected state. NavigationBar subview tree might get corrupted.
I do not know why.
METHOD 1:
Use
- (void)presentViewController:(UIViewController *)viewControllerToPresent
animated:(BOOL)flag
completion:(void (^)(void))completion
to present your _loginViewCtrl
METHOD 2:
Test whether logined in
- (BOOL)tabBarController:(UITabBarController *)tabBarController
shouldSelectViewController:(UIViewController *)viewController

Hide and Unhide masterView from button press of detailView

I know this question has asked by many users,But i did not found any answer related to my issue.
I'm using UISplitViewController ,my application starts with login page, so i have hidden masterView on start, after some time on DetailViewController i shown the master viewController using Delegate method.
- (BOOL)splitViewController:(UISplitViewController *)svc shouldHideViewController:(UIViewController *)vc inOrientation:(UIInterfaceOrientation)orientation NS_AVAILABLE_IOS(5_0)
{
return hideMaster;
}
i have initialised hideMaster to NO ,and my ViewDidLoad() of DetailViewController is below
ViewDidLoad(){
[self.splitViewController.view setNeedsLayout];
self.splitViewController.delegate =Nil;
self.splitViewController.delegate = self;
[self.splitViewController willRotateToInterfaceOrientation:[UIApplication sharedApplication].statusBarOrientation duration:0];
[super viewDidLoad];
}
it worked fine my master is now unhide.But on the same detailViewController i have a Back Button on which i'm poping the current ViewController to last viewController and again i want to hide masterViewController my code for back button is below.
- (IBAction)back:(id)sender {
hideMaster = NO;
self.splitViewController.delegate =Nil;
self.splitViewController.delegate = self;
[self.splitViewController willRotateToInterfaceOrientation:[UIApplication sharedApplication].statusBarOrientation duration:0];
[self.navigationController popViewControllerAnimated:NO];
}
Its poping the CurrentViewController to last ViewController but its not Hiding the masterViewController
Please help me out.
#JohnD,I went through your code.you are hiding the master view controller while poping the last View controller,but the viewController to which you are navigating is still showing the master View controller.therefore your masterView is still there.
follow the steps given below.
1.make delegate of UInavigationController to that ViewController which is your last singleView controller.
2.In last single ViewController(which is delegate of UINavigationController) implement following delegate method.
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
[self.splitViewController.view setNeedsLayout];
self.splitViewController.delegate =Nil;
self.splitViewController.delegate = self;
[self.splitViewController willRotateToInterfaceOrientation:[UIApplication sharedApplication].statusBarOrientation duration:0];
}
3.Now implement delegate method of UISplitViewController in side lastViewController which is given below.
- (BOOL)splitViewController:(UISplitViewController *)svc shouldHideViewController:(UIViewController *)vc inOrientation:(UIInterfaceOrientation)orientation NS_AVAILABLE_IOS(5_0)
{
return hideMaster;<<===============I'm assuming hide master as a variable of shared object(Singleton).
}
4.Now change your - (IBAction)back:(id)sender method with following one.
- (IBAction)back:(id)sender {
hideMaster = Yes;
[self.navigationController popViewControllerAnimated:NO];
}
I hope this will work,if you stuck some where please let me know.
you are using UISplitViewController inside your app,since you have many views but whole app is not using UISplitViewController only one view using it.
Its better to use another approach.

click navigation tabbaritem popToRootViewController

first I Install TabBarController directly as a window’s root view controller,and hava a NavigationController in viewControllers.
when the app run, I push some new viewcontroller onto the navigation stack
than I tap navigation tabbaritem, the navigationController
poptoRootViewController
How can I crash the step 3 event or stop it pop to root?
My solution to stop auto pop to root viewcontroller:
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
UITabBarController *tbc = [[UITabBarController alloc]init];
tbc.viewControllers = [NSArray arrayWithObjects:rvc,nil];
tbc.delegate = self;}
-(BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController{
if([tabBarController selectedViewController] == viewController)
return NO;
return YES;}
if you have an anther solution,wellcome write down.
try this code in tab bar app
[self.tabBarController.navigationController popToRootViewControllerAnimated:YES];
You implement didSelectViewController method in new viewController(push to new viewController)
Import UITabBarControllerDelegate,
- (void)viewDidLoad
{
[super viewDidLoad];
self.tabBarController.delegate = self;
}
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
{
[self.tabBarController.navigationController popToRootViewControllerAnimated:YES];
}

Resources