I am looking today for some insight into the issue that I am facing with my app.
I have a tab bar based application (3 tabs). In tab #2, here's the sequence of events.
"Add" button clicked in the rootView of tab #2.
Table View with navBar presented modally (PresentViewController).
Table Row touched.
New UINavigationController presented with it's rootViewController showing a few images
One of the images is selected
Present new view modally with navBar (presentViewController) with Image and details.
7 Upon clicking the image, I want to go back to the root view of tab # 2. (and I am using delegates for this)
My problem is that
=> Unless I dismiss each and every modal view, I am unable to go to the tab# 2.
=> If I am using delegate and setting the selectedTabIndex = 1 in the delegate the rootViewController of tab #2 should get displayed.
=> But In actuality that doesn't happen till i dismiss both modal view controllers. Why is that?
I read in the apple documentation that if you dismiss a modal view controller then all the subsequent view controllers would be dismissed as well. This however does not seem to be the case. I can get back to the root view controller of tab#2 only after I dismiss each and every modal view.
//AppDelegate :
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.tabBarController = [[UITabBarController alloc] init];
self.secondViewController = [[SecondViewController alloc] initWithNibName:nil bundle:nil];
self.navControllerTwo = [[UINavigationController alloc] initWithRootViewController:self.secondViewController];
//navControllerOne and viewControllerOne are also init'd here
NSArray *viewControllers = [NSArray arrayWithObjects:self.navControllerOne, self.navControllerTwo, self.viewControllerOne, nil];
[self.tabBarController setViewControllers:viewControllers];
self.window.rootViewController = self.tabBarController;
[self.window makeKeyAndVisible];
return YES;
}
// Then => 1. "Add" button clicked in the rootView of tab #2.
- (void)addItemButtonClicked:(id)sender
{
UIBarButtonItem *btn = nil;
AddItemViewcontroller *addItemController = [[AddItemViewcontroller alloc] initWithNibName:nil bundle:nil];
addItemController.delegate = self;
UINavigationController *addItemNavController = [[UINavigationController alloc] initWithRootViewController:addItemController];
//leftBaButton
btn = [[UIBarButtonItem alloc] initWithTitle:#"Cancel"
style:UIBarButtonItemStylePlain
target:self
action:#selector(addItemCancelButtonPressed:)];
addItemNavController.navigationBar.topItem.leftBarButtonItem = btn;
[self presentViewController:addItemNavController animated:YES completion:nil]; // First Modal View presented
}
//Then: => 2. Table View with navBar presented modally (PresentViewController).
// 3. Table Row touched.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
IGViewController *gvc = [[IGViewController alloc] initWithItemType:itemType]; // pre-determined item type
[self. navigationController pushViewController:gvc animated:YES];
}
//Then: 4. New UINavigationController presented with it's rootViewController showing a few images
// 5. One of the images is selected
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath;
{
UIBarButtonItem *btn;
UINavigationItem *navItem = [[UINavigationItem alloc] init];
UINavigationBar *navBar = [[UINavigationBar alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.view.frame), 44)];
SIViewController *siViewController = [[SIViewController alloc] initWithNibName:nil bundle:nil];
siViewController.delegate = self.appDelegate.secondViewController; // Init'd in the app delegate
btn = [[UIBarButtonItem alloc] initWithTitle:#"Add item" style:UIBarButtonItemStyleDone
target:selectedItemViewController
action:#selector(selectedItemViewAddItemButtonPressed)];
[navItem setLeftBarButtonItem:btn];
navBar.items = [NSArray arrayWithObject:navItem];
[navBar setAutoresizingMask:UIViewAutoresizingFlexibleWidth];
[selectedItemViewController.view addSubview:navBar];
[self presentViewController:selectedItemViewController animated:YES completion:nil]; //second modal view presentd here
}
//Then: 6. Present new view modally with navBar (presentViewController) with Image and details.
// 7 Upon clicking the image, I want to go back to the root view of tab # 2. (and I am using delegates for this)
-(void)siViewAddItemButtonPressed
{
[self.delegate selectedItemViewAddItemButtonPressedForItem:self.selectedItem];
}
//And: Here's what the method in the siViewControllers delegate looks like:
//In this routine setSelectedIndex = 2 does not work until i dismiss both modally presented views
- (void)siViewAddItemButtonPressedForItem:(Item *)item
{
[self.presentedViewController dismissViewControllerAnimated:NO completion:nil]; // Dismiss modal
[(UINavigationController*)(self.presentedViewController) popToRootViewControllerAnimated:NO];
[self.presentedViewController dismissViewControllerAnimated:NO completion:nil]; //Dismiss modal
}
Related
I want to load SFSafariViewController inside of a tab, so the tab bar is at the bottom of the entire Safari view.
Is this possible? I tried this with no luck:
[self.tabBarController presentViewController:sfController animated:YES completion:nil];
Is it required that the Safari view be full screen?
I was able to achieve this programmatically. They key to not have the UITabBar overlay on top of your UIViewController is to set translucent to NO:
In your AppDelegate.m:
#import SafariServices;
// ...
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
UITabBarController *tabBarController = [[UITabBarController alloc] init];
tabBarController.tabBar.translucent = NO;
SFSafariViewController *firstVC = [[SFSafariViewController alloc] initWithURL:[NSURL URLWithString:#"http://stackoverflow.com"]];
firstVC.title = #"SFSafariViewController";
UIViewController *secondVC = [[UIViewController alloc] init];
secondVC.view.backgroundColor = [UIColor blueColor];
secondVC.title = #"Blue VC";
tabBarController.viewControllers = #[firstVC, secondVC];
self.window.rootViewController = tabBarController;
[self.window makeKeyAndVisible];
return YES;
}
Using JAL's answer as a base, I was able to implement this myself in an app that had existing structure with tabs already.
I wanted tab #3 to go into a Safari controller within the tab after a button was pressed on the existing view, and not pop the Safari controller into its own window like it does using Apple's default code.
The key was to swap in a SFSafariViewController into the existing UITabBarController's array of view controllers. I saved the existing original view controller on tab #3 (index 2) to come back to it when the Done button was pressed on the Safari controller.
Here's what I did to go into the Safari controller from with my tab when a button was pressed:
NSMutableArray *viewArray = [NSMutableArray arrayWithArray:self.tabBarController.viewControllers];
self.savedController = [viewArray objectAtIndex:2];
[viewArray replaceObjectAtIndex:2 withObject:safariController];
self.tabBarController.viewControllers = viewArray;
[self setTabIconTitle];
Then I could swap back to the original view on that tab like this when the Done button was pressed on the Safari controller using this delegate call:
- (void)safariViewControllerDidFinish:(SFSafariViewController *)controller
{
UITabBarController *tabBarController = (UITabBarController *)self.window.rootViewController;
NSMutableArray *viewArray = [NSMutableArray arrayWithArray:tabBarController.viewControllers];
[viewArray replaceObjectAtIndex:2 withObject:self.savedController];
tabBarController.viewControllers = viewArray;
[self setTabIconTitle];
}
When I swapped controllers in an out of the tabBarController view controller array, I lost my tab icon and tab name, so I had to set those. Here is how I fixed that issue (and kept my theming when the tab icon was touched):
- (void)setTabIconTitle
{
UITabBarController *tabBarController = (UITabBarController *)self.window.rootViewController;
UITabBar *tabBar = tabBarController.tabBar;
UITabBarItem *marketplaceTab = [tabBar.items objectAtIndex:2];
marketplaceTab.image = [[UIImage imageNamed:#"tab2-icon"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
marketplaceTab.selectedImage = [UIImage imageNamed:#"tab2-icon"];
marketplaceTab.title = #"My Tab";
}
I must admit that I am not sure that Apple intended that the SFSafariViewController be used in this way within a tab, based on what the normal behavior of calling SFSafariViewController currently does. Just be aware that future iOS updates may change this behavior and always test your code when new iOS versions go into Beta.
I want to go to a view controller when the button "Cancel" is pressed. I tried using this method but when I click 'Cancel", it just displays a black screen. I am a beginner at IOS.
-(void) cancelButtonPressed {
homeView = (HomeViewController *)[[UIViewController alloc]init];
[self presentViewController:homeView animated:YES completion:nil];
}
EDITED FOR COMMENTS:
UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc]initWithTitle:#"Cancel" style:UIBarButtonItemStylePlain target:self action:#selector(cancelButtonPressed)];
self.navigationItem.leftBarButtonItem = cancelButton;
Try doing this:
HomeViewController *homeView = [[HomeViewController alloc]init];
[self presentViewController:homeView animated:YES completion:nil];
Also note that black is the default colour of the window. If you don't have any view controller named HomeViewController, and you present it, by default it will be visible as black colour to the user.
To Avoid this, you need to set the View for the newly presented view controller, which you can access by homeView.view
If you are using storyboard, then use storyboard ID:
HomeViewController *homeView = [self.storyboard instantiateViewControllerWithIdentifier:#"HomeViewController"];
[self presentViewController:homeView animated:YES completion:nil];
I push new StatusViewController(i created UITabbarViewController programmically in it) from rootviewController (UInavigation controller). Now, i want to click on logout button, it push rootviewcontroller but i used below code, it push rootviewcontroller fine but it still tabbar at the bottom.
This code to call rootviewcontroller:
LoginTab *loginView = [[LoginTab alloc] init];
[self.navigationController pushViewController:loginView animated:YES];
[loginView release];
And this code is created UItabbarcontroller in StatusViewController:
self.tab=[[UITabBarController alloc]init];
UploadTab *uploadview=[[UploadTab alloc]initWithNibName:nil bundle:nil];
UINavigationController *uploadTabItem = [[[UINavigationController alloc] initWithRootViewController: uploadview] autorelease];
uploadview.title=#"Uploading";
uploadview.tabBarItem.image=[UIImage imageNamed:#"Uploading.png"];
self.title = #"FirstViewControllerTitle";
//SecondViewController
ConvertTab *convertView=[[ConvertTab alloc]initWithNibName:nil bundle:nil];
UINavigationController *convertTabItem = [[[UINavigationController alloc] initWithRootViewController: convertView] autorelease];
convertView.title=#"Convert";
convertView.tabBarItem.image=[UIImage imageNamed:#"Convert.png"];
//ThirdViewController
CompletedTab *completedView=[[CompletedTab alloc]initWithNibName:nil bundle:nil];
UINavigationController *completedTabItem = [[[UINavigationController alloc] initWithRootViewController: completedView] autorelease];
completedView.title=#"Completed";
completedView.tabBarItem.image=[UIImage imageNamed:#"Completed.png"];
UIBarButtonItem * LogoutItem= [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:#"Logout.png"] style:UIBarButtonItemStylePlain target:self action:#selector(logout)];
self.navigationItem.rightBarButtonItem = LogoutItem;
self.tab.viewControllers=[NSArray arrayWithObjects:uploadTabItem,convertTabItem, completedTabItem, nil];
// [self.view insertSubview:self.tab.view belowSubview: uploadview.view];
[self presentModalViewController:self.tab animated:NO];
You can see this image :
Use popToRootViewControllerAnimated method instead of pushViewController:
[self.navigationController popToRootViewControllerAnimated:animated];
Your hierarchy does not seem correct. Your tab bar controller should be the root view controller. For each tab, you can have a navigation controller which has its own controllers to push and pop. That said, your tab bar will always be visible since that is the behavior that is expected when you have a tab bar based app. If you want to present a view which does not show a tab bar, you will need to present that view controller as a Modal view controller on top of your tab bar controller.
My goal is to create an application which features the camera as the first view that appears and then after taking a picture goes to a series of views which are in a navigation controller. The closest existing application to what I want to make is Snapchat.
I've been struggling with this for several days, here's what I have tried (none of these seem to work).
Root View (Inside Navigation Controller) Presents a Modal UIImagePickerController and then segues to next view. [Does not segue]
Same as 1, but dismiss the modal controller then segue. [Kinda Works. Shows the background when loading the UIImagePicker and also when transitioning to the next view]
Use a subclass of UIIMagePickerController as the root view.[Works but does not allow navigation bar to be shown or else crashes on displaying the UIImagePickerController][
Use 3 and don't embed inside a navigation controller (reasoning: since UIImagePickerController is a subclass of navigation controller this should work). [Does not work.]
I've tried about 10 other ways to do the same thing and they fall in this category: [Kinda Works. Most crash or look look ugly].
What is the best way to do this? Any help or advice would be greatly appreciated!
Again if this is confusing, just open snapchat and play with the flow (same flow, totally different idea for the actual app - ie. not a snapchat clone :)
Thanks!
If you present the image picker modally from the navigation controller's root view controller with no animation, then the picker is what you will see first. When you dismiss it, you'll see that root controller, which should be what ever you want to see first when the picker goes away. Is that what you want? This code would be in the root controller:
-(void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
static int first = 1;
if (first) {
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.sourceType = 0;
[self presentViewController:picker animated:NO completion:nil];
first = 0;
}
}
1st Suggestion:
Make one mainController and add the buttons(depends on how many viewController you have), when button clicked each button will load different viewController.
// appDelegate.h
#property (strong, nonatomic) UIWindow *window;
#property (strong, nonatomic) MainViewController *mainController;
//appDelegate.m
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
self.mainController = [[[MainViewController alloc] initWithNibName:#"MainViewController" bundle:nil] autorelease];
self.window.rootViewController = self.viewController;
//each button clicked has following IBAction:
-(IBAction)button1Clicked:(id)sender
{
FirstViewController *firstVC = [[FirstViewController alloc]initWithNibName:#"FirstViewController" bundle:[NSBundle mainBundle]];
UINavigationController *navController = [[[UINavigationController alloc] initWithRootViewController:firstVC]autorelease];
[self presentModalViewController:navController animated:NO];
[addVC release];
}
//in FirstViewController.m
-(void)viewDidLoad
{
[super viewDidLoad];
self.title = #"xxxx ";
self.navigationItem.leftBarButtonItem = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel
target:self action:#selector(cancel_Clicked:)]autorelease];
}
-(void) cancel_Clicked:(id)sender {
[self dismissModalViewControllerAnimated:YES];
}
Note :
ViewController to be embedded inside a navigation controller, the following code has to be used;
UINavigationController *navController = [[[UINavigationController alloc] initWithRootViewController:firstVC]autorelease];
I have two programmatically created buttons you can see in my viewDidLoad method. On the modal window I have a button that calls the cancelSearch method via a delegate. When I place a breakpoint on my cancelSearch method it is hit, so I know my delegate is set up correct, but even though it calls this line [self dismissViewControllerAnimated:YES completion:nil]; it's not actually closing the modal window.
The code below is all from my main controller view.
- (void)viewDidLoad
{
[super viewDidLoad];
UIBarButtonItem *actionButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAction target:self action:#selector(showActionMenu:)];
actionButton.style = UIBarButtonItemStyleBordered;
UIBarButtonItem *searchButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemSearch target:self action:#selector(showSearchMenu:)];
searchButtonItem.style = UIBarButtonItemStyleBordered;
UIToolbar* toolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 103.0f, 44.01f)];
NSArray* buttons = [NSArray arrayWithObjects:actionButton, searchButtonItem, nil];
[toolbar setItems:buttons animated:NO];
self.navigationItem.title = #"Census Management";
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:toolbar];
[[RKClient sharedClient] get:#"censusmanagement" delegate:self];
}
- (IBAction)showActionMenu:(id)sender
{
[self performSegueWithIdentifier: #"CMActionSegue" sender: self];
}
- (IBAction)showSearchMenu:(id)sender
{
ehrxCMSearchView *search = [[self storyboard] instantiateViewControllerWithIdentifier:#"cmSearch"];
search.selectedOptions = self.selectedOptions;
search.delegate = self;
[self.navigationController pushViewController:search animated:YES];
}
- (void)cancelSearch:(ehrxCMSearchView *)controller
{
[self dismissViewControllerAnimated:YES completion:nil];
}
You would dismiss a modal view using something similar to:
[self dismissModalViewControllerAnimated:YES];
This will dismiss the modal view which was loaded using something similar to:
[self presentModalViewController:search animated:YES];
However looking at your code snippet, it appears the search view controller is being pushed onto the navigation stack using the following line:
[self.navigationController pushViewController:search animated:YES];
So I you probably need to pop the view from the navigation stack rather than trying to dismiss it as a modal view:
[self.navigationController popViewControllerAnimated:YES];
If your view controller is modally presented, you should use this:
[self.presentingViewController dismissModalViewControllerAnimated:YES];
The presentingViewController property is available in iOS 5 only. So, if you're targeting older versions of iOS, you have to use self.parentViewController instead (use the appropriate one for each iOS version, you have to handle this).
If you make this control in your parent/presenting view controller, then just call this:
[self dismissModalViewControllerAnimated:YES];