I have a tab bar controller with five buttons. That controller has a tab view controller.
The tab view controller should behave differently depending on the tab being pressed.
For example, if the tab is "location", then the displayed data should be sorted based on location. If the tab is "alphabet", then the view should be sorted based on the alphabet.
I have this code in the view controller
-(void)viewWillAppear:(BOOL)animated
{
[super viewDidLoad];
[BNUtilitiesQuick parseXMLFileAtURL:#"http://example.com/BusinessSerialized.xml"];
[BNUtilitiesQuick UtilitiesQuick].BizsToDisplay = [BNUtilitiesQuick searchObjectsInContext:#"Business" :nil :#"Title" :YES];
NSLog(#"%#",[self tabBarController]);
if ([[self tabBarController]selectedIndex]==0)
{
}
NSLog(#"%d",[[self tabBarController] selectedIndex]);
// Do any additional setup after loading the view from its nib.
}
That [[self tabBarController] selectedIndex] works, except for one problem. Rather than giving the current selected index, it's the previous index.
Say I am now selecting tab 0, and I click tab 4; that NSLog() will display 0.
How can I solve this? I want to know the tab being pressed.
By using this delegate method you will be getting your selected index:
# enter code here
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
{
NSLog(#"sff %d",tabBarController.selectedIndex);
}
Related
I have created a tab bar view controller with 3 bar item, in storyboard.
Now on tap of a tab bar item I want to present a ViewController which is connected to tab bar item via Navigation controller.
How this can be achieved programmatically since I have not created any tab bar object.
(OR)
Is there a way to capture the tab bar item selection (which is created in storyboard)
Thank You...
Add this in viewDidLoad: to assign view controllers to each of the buttons:
self.tabBarController.viewControllers =
#[firstViewController,secondViewController,thirdViewController];
Here is how to detect the tap of the button:
-(void) tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
{
if (tabBarController.selectedIndex == 0) {
// present your first view controller
}
else if (tabBarController.selectedIndex == 1) {
// present your second view controller
}
else if (tabBarController.selectedIndex == 2) {
// present your third view controller
}
}
Use the UITabBarControllerDelegate to get notified about which tab got selected.
I have a NavigationController then a TabBarController which has Four Tabs.
I wanted to display Different titles on TopBar when a Different Tab is selected.
One way was to Embed each TabBarItem View into Navigation Controller but for some reason this doesn't seems the correct way, i wanted to apply this via code.
I managed accomplish this by using this code: (Products_ViewController.m custom class)
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
UINavigationController *navCon = (UINavigationController*) [self.navigationController.viewControllers objectAtIndex:0];
navCon.navigationItem.title = #"Products";
}
But the problem is now when a tab is clicked First time, it changes the title but then it doesn't. I then applied the same code on -(void)viewDidAppear{} but still the same result.
How can i manage to display navigation top bar title (or run the above code) whenever the tab bar item is clicked or the view is shown?
Thanks!
You could implement the UITabBarControllerDelegate in the Products_ViewController.m class and execute your code in the tabBarController:didSelectViewController: method.
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController {
UINavigationController *navCon = (UINavigationController*) [self.navigationController.viewControllers objectAtIndex:0];
navCon.navigationItem.title = #"Products";
}
In the viewDidLoad method you have to set the delegate to self.
I have implemented a custom version of a search form that behaves a lot like a UISearchBar with a scope bar (but is actually pieced together programatically for UI reasons). The screen loads with a TextField, you tap in the TextField and the navigation bar animates up off the screen, the text field moves up and a segmented control appears for filtering results.
Anyway, that all works, but when I tap on one of the search results my code pushes a new ViewController. The problem is that new controller gets pushed without a navigation bar (because I used [[self navigationController] setNavigationBarHidden:YES animated:YES] when switching to the search state).
I can show the navigation bar as the new ViewController gets pushed, or even animate it in as the transition to the new ViewController appears - but all those solutions look clunky. I want it to work as if you were using a UISearchBar (actually more like the email app) in that the restored navigation bar appears to just slide in from the right as if it's part of the child view controller.
I'm hoping there'll be a simple fix... thanks
For anyone that comes to this, the solution is to make your controller the delegate of the UINavigationController, then show or hide the nav bar in your delegate methods.
Your controller needs to implement the protocol:
#interface MYSearchController() <UINavigationControllerDelegate>
Then in -(void)viewDidLoad assign your controller as the delegate:
[self navigationController].delegate = self;
Finally, implement a method like this:
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
if(viewController == self)
{
if(_searchState && ![self navigationController].navigationBarHidden)
{
[[self navigationController] setNavigationBarHidden:YES animated:YES];
}
}
else
{
if([self navigationController].navigationBarHidden)
{
[[self navigationController] setNavigationBarHidden:NO animated:YES];
}
}
}
I have a view with a custom bar at the bottom of the screen. When a collection view cell is pressed, it loads a detail view, and I can go back.
This all works great; however, I have a plus button displayed on the custom bar, and I would like for the plus button to disappear only when the detail view shows up, and then come back when you hit the back button.
So far I have used the delegate method:
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
// Your code to update the parent view
}
The problem is this fires when the detail view is loaded and popped as well. Any idea on how to accomplish this? Thanks!
I assume mainView and detailView are viewControllers. In mainView's viewWillAppear method
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
//get reference of plus button here
btnPlus.hidden = NO;
}
In detailView's viewWillAppear method
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
//get reference of plus button here
btnPlus.hidden = YES;
}
I'm converting an iPhone app to be a universal app, and it's been mostly straight forward to convert the nested tables into a UISplitViewController arrangement, but I have a remaining issue when running on an iPad that is giving me a headache.
For universal app compatibility, the 'master' view contains a UINavigationController that is used to navigate through a series of TableViews that each displays a menu. This works fine.
Eventually, the user arrives at content that is displayed in the detail view. Each detail view 'chain' is contained in a UINavigationController, as some views can drill down to show maps etc. The idea is that the popover button will live at the root level of the detail view. It's probably important to note that the detail views are created from scratch every time that row is selected.
I've studied Apple's Multiple Detail View Sample Code , and so use the master view as the UISplitViewController delegate, which provides the hide/show popover selectors, and then passes the calls down to whichever substitute detail view is selected.
When working in landscape mode, I can select different rows in the master view, and the detail views switch nicely - everything works great. It's wonderful.
In portrait mode, things don't work quite so well... the popover button displays correctly in the currently selected detail view when rotating to portrait, but then disappears when a row is selected (i.e. it's somehow not being added correctly to the newly selected view's NavBar).
I've added diagnostic code, and it looks like the correct calls (with correct pointers) are being made to show the popover button on the newly selected detail view. Also, I can rotate to landscape and back again, and the popover button then appears so I'm reasonably satisfied that the popover UIBarButtonItem is being hooked up to the new detail NavBar correctly.
As the detail views are not created until the row is selected, I was wondering if this was a case of the UINavigationBar not being instantiated at the time that showRootPopoverButtonItem is called (based on Apple's sample code). This theory is supported by the fact that the popover button appears if I rotate to landscape and back again (as mentioned above) with the same view selected.
I also see this comment in Apple's sample code, in didSelectRowAtIndexPath, and just before switching the detail views, note the use of the word 'after'...
// Configure the new view controller's popover button (after the view has been displayed and its toolbar/navigation bar has been created).
So, I tried calling the showRootPopoverButton method again in viewWillAppear (by which time the UINavigationBar should exist), but that doesn't cause the popover button to appear either.
I'd appreciate any thoughts and suggestions as to how to get the popover button to appear immediately when a new row is selected from the master view when in portrait mode. Thanks.
Thanks for reading this far, the relevant code is below.
From the master view, here are the UISplitViewControllerDelegate selectors,
- (void)splitViewController:(UISplitViewController*)svc willHideViewController:(UIViewController *)aViewController withBarButtonItem:(UIBarButtonItem*)barButtonItem forPopoverController:(UIPopoverController*)pc
{
// Keep references to the popover controller and the popover button, and tell the detail view controller to show the button.
barButtonItem.title = #"Root View Controller";
self.popoverController = pc;
self.rootPopoverButtonItem = barButtonItem;
//UIViewController <SubstitutableDetailViewController> *detailViewController = [self.splitViewController.viewControllers objectAtIndex:1];
// ^ Apple's example, commented out, my equivalent code to obtain
// active detail navigation controller below,
UINavigationController *detailNavController = [self.splitViewController.viewControllers objectAtIndex:1];
UIViewController *detailViewController = detailNavController.visibleViewController;
[detailViewController showRootPopoverButtonItem:rootPopoverButtonItem];
}
- (void)splitViewController:(UISplitViewController*)svc willShowViewController:(UIViewController *)aViewController invalidatingBarButtonItem:(UIBarButtonItem *)barButtonItem
{
// Nil out references to the popover controller and the popover button, and tell the detail view controller to hide the button.
UINavigationController *detailNavController = [self.splitViewController.viewControllers objectAtIndex:1];
UIViewController *detailViewController = detailNavController.visibleViewController;
[detailViewController invalidateRootPopoverButtonItem:rootPopoverButtonItem];
self.popoverController = nil;
self.rootPopoverButtonItem = nil;
}
And, very much like Apple's example, here's what happens when a row is selected in the master table,
if (rootPopoverButtonItem != nil)
{
NSLog (#"show popover button");
[newDetailViewController showRootPopoverButtonItem:self.rootPopoverButtonItem];
}
From the detail view,
- (void)showRootPopoverButtonItem:(UIBarButtonItem *)barButtonItem
{
NSLog (#"detailViewController (view: %p, button: %p, nav: %p): showRootPopoverButton", self, barButtonItem, self.navigationItem);
barButtonItem.title = self.navigationItem.title;
[self.navigationItem setLeftBarButtonItem:barButtonItem animated:NO];
popoverButton = barButtonItem;
}
- (void)invalidateRootPopoverButtonItem:(UIBarButtonItem *)barButtonItem
{
NSLog (#"detailViewController (%p): invalidateRootPopoverButton", self);
// Called when the view is shown again in the split view, invalidating the button and popover controller.
[self.navigationItem setLeftBarButtonItem:nil animated:NO];
popoverButton = nil;
}
There are two things that I think could be the problem here. You should include the rest of your code. Specifically the part where you change the detail view controller when the user performs an action in the master.
visibleViewController may be nil if you just instantiated detailNavController. Even if you set it's root, there is no "visible" view controller since it actually hasn't displayed yet. You may want to try using topViewController
I'm not sure if you're creating a new detailNavController every time the user selects something in the master but if you are, you need to pass the rootPopoverButtonItem into the detailViewController again because - (void)splitViewController: willHideViewController: withBarButtonItem: forPopoverController: only gets called automatically when the orientation changes.