I have used the following code for deleting my login page from the navigationcontroller(viewcontrollers) so that it will not come into the view again when going back (back button).
if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
{
NSMutableArray *VCs = [NSMutableArray arrayWithArray:self.navigationController.viewControllers];
if([[VCs objectAtIndex:[VCs count] - 2] isKindOfClass:[loginViewController class]]&&(VCs.count>=4))
{
[VCs removeObjectAtIndex:[VCs count] - 2];
[VCs removeObjectAtIndex:[VCs count] - 2];
[self.navigationController setViewControllers: VCs];
}
}
This works perfectly for iPhone. But for iPad, since we are using splitViewController, if we code like
NSMutableArray *VCs = [NSMutableArray arrayWithArray:self.splitViewController.viewControllers];
What we will be getting is an array of navigationControllers. Is there a genuine logic by which we can delete a particular viewcontroller from the splitviewcontroller?
Your split view controller, as you said, will return an array of nav controllers (depending on the project setup). Once you have a reference to those, you can manipulate them however you want.
UISplitViewController *splitViewController = (UISplitViewController *)self.window.rootViewController;
UINavigationController *masterNavVC = (UINavigationController *)splitViewController.viewControllers.firstObject;
UINavigationController *detailNavVC = (UINavigationController *)splitViewController.viewControllers.lastObject;
//Now you have the master and detail navigation controllers, get your VC you need to manipulate
NSMutableArray *masterVCs = masterNavVC.viewControllers;
NSMutableArray *detailVCs = detailNavVC.viewControllers;
//Remove the ones you need to - this example is arbitrary. Put your logic here
if(masterVCs.count > 0 && [masterVCs[0] isKindOfClass:[LoginViewController class]])
{
//Remove or add
}
I have three viewcontollers in my navigation controller. Now what i want to do just insert a view controller in between the array of self.navigationController.viewControllers.
As I checked the property viewControllers is not a readonly property So i think we can set it also.
thats why I used the below code to insert my ViewController in between the stack.
But unfortunately it doesn't modify the stack of self.navigationController.viewControllers.
So how can I insert and modify the stack. Also be sure that I don't want to pushViewcontroller.
CXSTransactionSelectionViewController *trxSelectionVc = [self.storyboard instantiateViewControllerWithIdentifier:#"CXSTransactionSelectionViewController"];
NSMutableArray *viewControllers = [self.navigationController.viewControllers mutableCopy];
[viewControllers insertObject:trxSelectionVc atIndex:viewControllers.count-2 ];
[self.navigationController setViewControllers:viewControllers animated:YES];
NSLog(#"%#",self.navigationController.viewControllers);
Try to do something like this:
NSArray * oldViewControllers = [self.navigationController viewControllers];
NSArray * newViewControllers = [NSArray arrayWithObjects:[oldViewControllers objectAtIndex:0], newVC, [oldViewControllers objectAtIndex:1],nil];
[self.navigationController setViewControllers:newViewControllers];
using this my problem is resolved
CXSTransactionSelectionViewController *trxSelectionVc = [self.storyboard instantiateViewControllerWithIdentifier:#"CXSTransactionSelectionViewController"];
[self.navigationController.viewControllers insertObject:trxSelectionVc atIndex:1 ];
NSLog(#"%#",self.navigationController.viewControllers);
I have the following storyboard setup
I need to jump from the BodyMapViewController to MoleDetailsView controller (as shown in the image) when the user hit the save button
I can use the modal view which is very easy but the issue is that I want the user to be able to go back to the MoleHistory and dermalHistory views from the MoleDetailsView
basically I need to do the following steps:
switch the tab
Navigate trough the DermalHistoryView and then MoleHistoryView to get to the MoleDetails view
The idea is that you need to switch tabs and manually modify the view hierarchy so the correct view is showing.
First, grab the navigation controller controlling the other tab. With that, you can then instantiate a view hierarchy with an NSMutableArray like follows:
-(void)pushToMoleDetailViewController:(id)detailItem
{
UINavigationController *navCon = [self.navigationController.tabBarController.viewControllers objectAtIndex: 1];
UIStoryboard *storyboard = self.storyboard;
DermalHistoryViewController *dermalHistory = [storyboard instantiateViewControllerWithIdentifier:#"DermalHistoryViewController"]
//configure dermal history here
NSMutableArray *viewControllers = [[self navigationController].viewControllers mutableCopy];
[viewControllers addObject: dermalHistory];
MoleHistoryViewController *moleHistory = [storyboard instantiateViewControllerWithIdentifier:#"MoleHistoryViewController"]
//configure mole history here
[viewControllers addObject: moleHistory];
MoleDetailsViewController *moleDetails = [storyboard instantiateViewControllerWithIdentifier:#"MoleDetailsViewController"]
//configure mole details here
[viewControllers addObject: moleDetails];
navCon.viewControllers = viewControllers;
self.navigationController.tabBarController.selectedIndex = 1;
}
Take a look at this question:
Push segue without animation
I am in kind of situation that I need to start with a tab based application and in that I need a split view for one or more tabs. But it seems that split view controller object can not be added to the tabbarController. (Although tabbar object can be added to the splitviewcontroller).
The problem can be seen otherways: I have a full screen in the left part I have a table view when any row is selected in the table a popover should come out pointing that row. Now when any row in the popover is selected the rows in this popover comes to the left under the selected row (only this row would be visible) and another popover comes out from the selected row. (Breadcrumb navigation type)
I think I am clear in what I explained. So guys any ideas or work arounds?
Please let me know if I am not clear in my question.
Thanks,
Madhup
Using the interface builder, create a split view controller and a tab bar controller and link them to your outlets:
#property (nonatomic, retain) IBOutlet UITabBarController *tabBarController;
#property (nonatomic, retain) IBOutlet UISplitViewController *splitViewController;
In your app delegate didFinishLaunchingWithOption, assign your split view controller to the tab bar controller:
splitViewController.tabBarItem = [[[UITabBarItem alloc] initWithTitle:#"Title" image:nil tag:0] autorelease];
NSArray *controllers = [NSArray arrayWithObjects:splitViewController, /* other controllers go here */ nil];
tabBarController.viewControllers = controllers;
[window addSubview:tabBarController.view];
[window makeKeyAndVisible];
This will create a tab bar controller (with only 1 tab in this case), which is displayed correctly in all orientations.
I've written up a subclass for the UISplitViewController that will listen for changes to device orientation and orient itself accordingly. With this class, I can now place split views within a UITabBarController and each split view will behave correctly upon rotation, even if it's not the frontmost tab. I've successfully deployed this in TexLege and it was approved for use in the App Store, but your mileage may vary. Please see the repository at Github.
Feel free to fork and modify it, and I'm always interested in hearing comments (or complaints) about it. https://github.com/grgcombs/IntelligentSplitViewController
I made a sample application. and found we can do it programmatically like:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSMutableArray *array = [NSMutableArray array];
NSMutableArray *tabArray = [NSMutableArray array];
UISplitViewController *splitViewConntroller = [[UISplitViewController alloc] init];
MainViewController *viewCont = [[MainViewController alloc] initWithNibName:#"MainViewController" bundle:nil];
[array addObject:viewCont];
[viewCont release];
viewCont = [[DetailViewController alloc] initWithNibName:#"DetailViewController" bundle:nil];
[array addObject:viewCont];
[viewCont release];
[splitViewConntroller setViewControllers:array];
[tabArray addObject:splitViewConntroller];
[splitViewConntroller release];
array = [NSMutableArray array];
splitViewConntroller = [[UISplitViewController alloc] init];
viewCont = [[MainViewController alloc] initWithNibName:#"MainViewController" bundle:nil];
[array addObject:viewCont];
[viewCont release];
viewCont = [[DetailViewController alloc] initWithNibName:#"DetailViewController" bundle:nil];
[array addObject:viewCont];
[viewCont release];
[splitViewConntroller setViewControllers:array];
[tabArray addObject:splitViewConntroller];
[splitViewConntroller release];
// Add the tab bar controller's current view as a subview of the window
[tabBarController setViewControllers:tabArray];
[window addSubview:tabBarController.view];
[window makeKeyAndVisible];
return YES;
}
Hope this helps.
To let a tabbarcontroller appear as a master view for splitviewcontroller you should rewrite tabbarcontroller so that it will support or orientations(so say, using a category for the class UITabBarController)
See my post about retrofitting split view controllers to an existing tab bar interface: http://markivsblog.blogspot.com/2010/04/retrofitting-ipad-uisplitviewcontroller.html
I created a UITabBarController subclass which properly propagates the rotation messages to all UISplitViewControllers it contains. This maintains the correct internal state of the UISplitViewControllers. However, one of the SplitViewController delegate methods is not called if the SplitViewController is not visible, so I account for this in the detail view controller viewWillAppear method. I've confirmed this works in iOS5.0 - iOS6.1
OSTabBarController.m
#import "OSTabBarController.h"
#implementation OSTabBarController
-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration{
[super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
for(UIViewController *targetController in self.viewControllers){
if(targetController != self.selectedViewController && [targetController isKindOfClass:[UISplitViewController class]]){
[targetController willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
}
}
}
-(void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation{
[super didRotateFromInterfaceOrientation:fromInterfaceOrientation];
for(UIViewController *targetController in self.viewControllers){
if(targetController != self.selectedViewController && [targetController isKindOfClass:[UISplitViewController class]]){
[targetController didRotateFromInterfaceOrientation:fromInterfaceOrientation];
}
}
}
#end
DetailViewController
#implementation OSDetailViewController
-(void)viewWillAppear:(BOOL)animated{
//the splitViewController:willHideViewController:withBarButtonItem:forPopoverController: may not have been called
if(!UIInterfaceOrientationIsPortrait(self.interfaceOrientation)){
self.navigationItem.leftBarButtonItem = nil;
}
}
#pragma mark - UISplitViewControllerDelegate Methods
- (void)splitViewController:(UISplitViewController *)splitController willHideViewController:(UIViewController *)viewController withBarButtonItem:(UIBarButtonItem *)barButtonItem forPopoverController:(UIPopoverController *)popoverController
{
[self.navigationItem setLeftBarButtonItem:barButtonItem animated:YES];
}
- (void)splitViewController:(UISplitViewController *)splitController willShowViewController:(UIViewController *)viewController invalidatingBarButtonItem:(UIBarButtonItem *)barButtonItem
{
[self.navigationItem setLeftBarButtonItem:nil animated:YES];
}
#end
Keep in mind that OS 3.2 does not provide proper support for a splitview as a tabbar view.
You can make it "work" but it will have bugs - the biggest is that an orientation change made on another tab's view will often not propagate to the splitview tab view properly, making the view go wacky when you go back to it (left side view takes over the screen, or the barbutton item is missing, etc.).
I've reached the conclusion that I have to create my own splitview for use in a tabBarController because of this issue.
I had heard rumors that Apple was working on a fix but it's been months now and no iPad OS updates have occurred - maybe OS 4 for the iPad will address it.
You can use IB to build tabtab and modify tabs to splitviewcontroller.
-(void) makeSplitViewController {
NSMutableArray *controllers = [NSMutableArray arrayWithArray:tabBarController.viewControllers];
int index = 0;
for (UIViewController *controller in tabBarController.viewControllers) {
if ([controller.tabBarItem.title isEqualToString:#"Stock"]) {
stockDetailController = [[StockDetailController alloc] initWithNibName:#"StockDetailController" bundle:nil];
stockMasterController = [[StockMasterController alloc] initWithStyle:UITableViewStylePlain];
stockMasterController.navigationItem.title = date;
stockMasterController.stockDetailController = stockDetailController;
UINavigationController *nav = [[[UINavigationController alloc] initWithRootViewController:stockMasterController] autorelease];
splitViewController = [[UISplitViewController alloc] init];
splitViewController.tabBarItem = controller.tabBarItem;
splitViewController.viewControllers = [NSArray arrayWithObjects:nav, stockDetailController, nil];
splitViewController.delegate = stockDetailController;
[controllers replaceObjectAtIndex:index withObject:splitViewController];
}
index++;
}
tabBarController.viewControllers = controllers;
}
We succeeded in having a UISplitViewController inside a UITabViewController on iPad with iOS5+.
to make a long story short: it works:
out of the box if you accept a split also in portrait;
with a bit of
work, if you want to have the master view hidden in portrait, and
have it appear only upon tapping a button.
The trick in the second case is to use the IntelligentSplitViewController (see a few posts up, thanx Greg Combs) or similarly extend a UISplitVC, and be careful that the delegate of the subclass of the splitview controller is always a live object.
We have detailed the process on:
https://devforums.apple.com/message/763572#763572
I have done a sample app with UISplitViewController studying the example they have provided. I have created three detailviews and have configured them to change by the default means. Either using the left/master view in landscape AND using the popover in the portrait orientation.
Now I am trying to move to another view(previous/next) from the currentView by using left/right swipe in each view. For that, what I did was just created a function in the RootViewController. I copy-pasted the same code as that of the tablerow selection used by the popover from the RootViewController. I am calling this function from my current view's controller and is passing the respective index of the view(to be displayed next) from the current view. Function is being called but nothing is happening.
Plz help me OR is anyother way to do it other than this complex step? I am giving the function that I used to change the view.
- (void) rearrangeViews:(int)viewRow
{
UIViewController <SubstitutableDetailViewController> *detailViewController = nil;
if (viewRow == 0) {
DetailViewController *newDetailViewController = [[DetailViewController alloc] initWithNibName:#"DetailView" bundle:nil];
detailViewController = newDetailViewController;
}
if (viewRow == 1) {
SecondDetailViewController *newDetailViewController = [[SecondDetailViewController alloc] initWithNibName:#"SecondDetailView" bundle:nil];
detailViewController = newDetailViewController;
}
if (viewRow == 2) {
ThirdDetailViewController *newDetailViewController = [[ThirdDetailViewController alloc] initWithNibName:#"ThirdDetailView" bundle:nil];
detailViewController = newDetailViewController;
}
// Update the split view controller's view controllers array.
NSArray *viewControllers = [[NSArray alloc] initWithObjects:self.navigationController, detailViewController, nil];
splitViewController.viewControllers = viewControllers;
[viewControllers release];
if (rootPopoverButtonItem != nil) {
[detailViewController showRootPopoverButtonItem:self.rootPopoverButtonItem];
}
[detailViewController release];
}
I have googled and found a nice approach. They use a UINavigationController on the detail view to push new views. You could use this same solution for your project.
http://www.cimgf.com/2010/05/24/fixing-the-uisplitviewcontroller-template/