I have UITabViewController running with UINavigationController. In each tab i have a different TableViews that are roots of my application tree.
When i click an item of table, it goes to next level viewing another, detailed TableView, still having TabBar and NavigationBar on screen. It works perfectly, except for one thing. If i'm viewing details in one tab, then switch to another tab, and go back again, then i still see my detail. What i want to achieve, is to reset tab after leaving it.
I expect that i have to put something in viewDidUnload or simmilar, but couldn't find the right solution.
Hope you can help.
at
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
do
[viewController.navigationController popToRootViewControllerAnimated:YES];
That will navigate the tab's view controller to the root view whenever the tab is selected.
That's completely OK to keep your main window view controller (tab bar controller) instance at application delegate.
What you need to add is to set the delegate or whatever other initialized class to be the tab bar controller's delegate like this:
myTabBarController = [UITabBarController alloc ...
myTabBarController.delegate = self; // the app delegate will be also the tab bar delegate
in the app delegate, then you add the following method to the app delegate:
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController{
[viewController.navigationController popToRootViewControllerAnimated:YES];
}
The tab bar controller will call this method whenever it's tab is selected.
You will also want to make the application delegate confirm UITabBarControllerDelegate this way:
#interface PSAppDelegate : UIResponder <UITabBarControllerDelegate>
that will let the compiler know that app delegate must or might have the methods declared in the protocol and will also give you so convenient auto-complition of this method.
One way to do this is to get the view controllers associated with the tabviewcontroller and then create new objects.
self.tabBarController?.viewControllers! will get an array of viewControllers for the tab bar. In my case they are a UINavigationControllers but they could be anything. I then get the viewController associated with that and reset that.
If you don't have navigation controllers you can just create new view controller objects and go with that.
below is the solution in my case (with the navcontroller)
let vc = self.tabBarController?.viewControllers![0] as! UINavigationController
let newVC = YourViewControllerClass()
vc.viewControllers[0] = newVC as UIViewController
This replaces the old (populated) vc with a new one!
Related
I have a UITabBarController with Tabs (say Tab1, Tab2, Tab3, Tab4) and UITabBarController is my RootViewController and I'm making an API Call in the same. Since it is a RootViewController I'm displaying Tab1 as my default View. When I get the results to my API Call in UITabBarController. I need to share the details in real time to my Tabs. I have tried few ideas(like NotificationCenter, Singleton Class) but it's not working out. Can somebody help me to fix this? Thanks in advance. If you have a working example I kindly request you to share it with me.
Img Representation:
UITabBarController has a property viewControllers that is an array of view controllers displayed (by index for tab position, but you probably don't need that). One simple solution is when your UITabBarController subclass gets data, it can loop over the viewControllers array and check each for delegate conformance / responds to selector and update accordingly.
That's probably the simplest. Another way would be to have the view controllers in the tabs register for updates. So they conform to a delegate protocol, and get a reference to their tab bar controller (the tab bar controller subclass), and call the tab bar saying "observe updates." The tab bar controller keeps storage of registered observing objects and calls each with new data.
This assumes you are setting the tab's view controllers in IB. If you are doing it programmatically, then with the second option you can just link the tabs to the tab bar controller when you add them. If set in IB you could also do it by overriding -prepareForSegue since embedding the tabs in the root is considered a segue, but you'd still have to cast the destinationViewController as whatever subclass can receive data.
The first option is simple enough and though I don't like casting, it's unavoidable to take advantage that the references you want are right there. Plus, there will in reality only ever be a single-digit number of tabs, so it can't get expensive. Hope this helps.
This is just same like passing the values to another viewController but here you need to use tabBarController's delegate method in below example:
Passing value using delegate method from controller A:
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
{
ControllerB *controllerB = (ControllerB *) [tabBarController.viewControllers objectAtIndex:1];
//In this example, there is only have 2 tab bar controllers (A and B)
//So, index 1 is where controller B resides and index 0 where controller A resides.
self.controllerB.data.text = #"some value!";
//This will change the text of the label in controller B
}
Getting value in controller B
// set property in controller B .h file
#property(strong, nonatomic) UILabel *data;
// in controller B .m file viewDidLoad method
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"getting data: %#",data.text); // getting value
}
How about
-Declare a delegate protocol, say, Tab1ViewControllerDelegate, with a method - (void) tab1ViewController:(Tab1ViewController *) tab1ViewController, didReceiveData: (NSDictionary *) data
make a TabBarController subclass a delegate of your tab1ViewController
when tab1ViewController gets it's data, call [self.delegate tab1ViewController: self, didReceiveData: datDict]
then your TabBarController can distribute the data to its array of viewControllers
Firstly, I have set both viewcontrollers to be UITabBarController delegates. Both are part of a tab bar controller. I did this by putting the following code into each viewDidLoad:
self.tabBarController.delegate = self;
Then I added the following delegate method to CalculatorsViewController:
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController {
[self presentCalculatorsView];
}
Where presentCalculators view simply reveals a subview within the same view controller.
I also added the following delegate method to the OptionsViewController:
-(void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController {
[self presentHomeScreen];
}
Again this method simply reveals another subview within the viewController.
The problem I am having is that the OptionsViewController presentHomeScreen method is only called if I do not visit the CalculatorsViewController. Once I do visit the CalculatorsViewController in the app and then return to OptionsViewController,
[self presentHomeScreen]
is never called. In fact, it appears that it still calls the method from the CalculatorsViewController. I tested it with an NSLog statement.
Any ideas why one method overrides the other? Or why the tab bar button executes code from another viewController, other than the one that is active?
EDIT* It is almost as if the one viewController 'steals' the delegate from the other.
By calling self.tabBarController.delegate = self; on each viewDidLoad method, you are basically telling the tab bar controller to use abandon the current delegate and use the current view controller as delegate.
Note that the viewDidLoad method is called only once under normal circumstances. (It may be called again when the view of your view controller is unloaded due to memory warning, for example, then you access the view of your view controller again, which calls loadView/awakeFromNib and viewDidLoad. I'm not entirely sure on this scenario though.) In your scenario:
Open OptionsViewController for the first time - tab bar controller's delegate is OptionsViewController
Open CalculatorsViewController for the first time - tab bar controller's delegate is now CalculatorsViewController
Go back to OptionsViewController - tab bar controller's delegate is still CalculatorsViewController, as the viewDidLoad is not called again
If you must change the delegate, you can do it instead in the viewWillAppear method.
I have 2 view controllers and a tab bar controller created in storyboard.
is it possible to execute a method in either of the 2 view controllers when the relevant tab bar is pressed?
Ive tried several ways but they need a nib name on the firstViewController or secondViewController if I want to initialize an object of the firstViewController, normally the firstViewController is just created on launch,
Any help would be appreciated, I'm vaguely familiar with the uitabcontroller app delegate but I don't know how to hook up the two view controllers to the tab controller
Have a look at the UITabViewController Delegate :
You use the UITabBarControllerDelegate protocol when you want to
augment the behavior of a tab bar. In particular, you can use it to
determine whether specific tabs should be selected, to perform actions
after a tab is selected, or to perform actions before or after the
user customizes the order of the tabs. After implementing these
methods in your custom object, you should then assign that object to
the delegate property of the corresponding UITabBarController object.
All of the methods in this protocol are optional.
Reference : http://developer.apple.com/library/ios/#DOCUMENTATION/UIKit/Reference/UITabBarControllerDelegate_Protocol/Reference/Reference.html
What you need should be achievable by implementing :
- (void)tabBarController:(UITabBarController *)tabBarController
didSelectViewController:(UIViewController *)viewController
If you are using storyboard, do this
in didFinishLaunchingWithOptions
UITabBarController *tabBar = (UITabBarController *)self.window.rootViewController;
[tabBar setDelegate:self];
And then
-(void) tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
{
//Write your code here
}
I got an app with my custom TabBar Controller Class.
I tried to implement tabbar controller delegate method:
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController {
NSLog(#"%i",tabBarController.selectedIndex);
}
But it doesnt work. Why?
in ViewDidLoad i write:
self.tabBarController.delegate = self;
And in .h i implement:
#interface BaseViewController : UITabBarController <UITabBarControllerDelegate>
In your custom TabBarController, do not use
self.tabBarController.delegate = self;
But use
self.delegate = self;
.tabBarController returns the nearest ancestor in the view controller hierarchy that is a tab bar controller, but your custom TabBarController IS the controller you want to target, so no need to search in its hierarchy
You have said, that it's your custom TabBarController. What is the customisation you've done? If you changed the TabBar panel and replaced it with your own to use
setSelectedIndex:
setSelectedViewController:
methods manually, then you should call delegate's methods manually too.
According to the Apple's documentation:
There are two types of user-initiated changes that can occur on a tab
bar:
The user can select a tab.
The user can rearrange the tabs.
Both types
of changes are reported to the tab bar controller’s delegate, which is
an object that conforms to the UITabBarControllerDelegate protocol.
Also check the UITabBarControllerDelegate Protocol Reference
In iOS v3.0 and later, the tab bar controller calls this method regardless of whether the > selected view controller changed. In addition, it is called only in response to user taps in > the tab bar and is not called when your code changes the tab bar contents programmatically.
Delegate will respond only if user interacts with its UITabBar control.
I got a tabbar application.
There is only 2 tabs in the tabbar. First tab is a NavigationController, there are two views in the NavigationController - root and detail views, second is a TableViewController. Second works perfect, but the the first doesn't.
I start in first view (NavigationController). Then go in this NavigationView to the detail view. Then, for example, i go to the second tabbar view. Then go back to the first, but i dont see the root view, but the detail view.
How can i open the root view every time?
Use the UITabBarController delegate method tabBarController:didSelectViewController: like this:
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController {
if (viewController != tabBarItemForNavControllerTab) {
[self.navControllerInFirstTab popToRootViewControllerAnimated:NO];
}
}
Also make sure that delegate is setup properly, when creating your UITabBarController and you change the code from my snippet to fit your controller names.