How to present modalViewController inside the masterViewController? - ios

I am doing an iPad app with UISplitViewController. I want to open a modalViewController in the masterViewController itself. When I load my view controller modally, it takes a whole screen to present it.
Here it is my code, which is in my masterViewController.m to present the new viewController modally
- (void)addNewContactButtonPressed:(id)sender {
AddOrEditContact *addContact = [self.storyboard instantiateViewControllerWithIdentifier:#"AddOrEditContact"];
addContact.screenMode = addMode;
UINavigationController *navigationController = [[UINavigationController alloc]initWithRootViewController:addContact];
[self.navigationController presentViewController:navigationController animated:YES completion:nil];
}
I want to load a new viewController modally inside the masterViewController. Any help would be appreciated.

You can't present a modal viewController over the masterViewController only, but you can add a childView controller to the masterViewController nd perform your own animation to present it
- (void)addiewControllerToHierarchy:(UIViewController *)viewController
{
[self addChildViewController:viewController];
[self.view addSubview:frontViewController.view];
if ([viewController respondsToSelector:#selector(didMoveToParentViewController:)])
{
[viewController didMoveToParentViewController:self];
}
}
and to remove
- (void)_removeViewControllerFromHierarchy:(UIViewController *)viewController
{
[viewController.view removeFromSuperview];
if ([viewController respondsToSelector:#selector(removeFromParentViewController)])
{
[viewController removeFromParentViewController];
}
}
this example doesn't have animation and probably you need to adjust the frame of the view etc... but I hope could help you

Related

how to hide navigation controller number 1 instead navigation controller number 2 inside navigation controller number 1

2 Controllers
PageviewController
1)
- (void)applicationDidFinishLaunching:(UIApplication *)application
[self.window setRootViewController:navigationController];
On bottom toolbar button click in view pushing second UINavigationController:
[self.navigationController pushViewController:cnController animated:YES];
Loading of UIPageViewController in UINNavigationController:
#interface SwipeBetweenViewControllers : UINavigationController <UIPageViewControllerDelegate,UIPageViewControllerDataSource,UIScrollViewDelegate>
On bottom toolbar button click in view:
SampleViewController *viewController = [[SampleViewController alloc] initWithStyle:UITableViewStyleGrouped];
viewController.model = settingsModel;
viewController.navigationItem.title = #"Settings";
[viewController willMoveToParentViewController:self];
// [[self navigationController] setNavigationBarHidden:YES animated:YES];
[self.view addSubview:viewController.view];
[self addChildViewController: viewController];
[viewController didMoveToParentViewController:self];
[self.navigationController pushViewController:viewController animated:YES];
It shows 2 navigation controllers. I need to hide the top one when I issue following:
[[self navigationController] setNavigationBarHidden:YES animated:YES];
It hides UIPageviewcontroller navigation and go back to original view. I also tried:
NSMutableArray *allControllers = [self.navigationController.viewControllers mutableCopy];
[allControllers removeObjectAtIndex:allControllers.count -1];
and also
for (UIViewController *controller in self.navigationController.viewControllers)
{
if ([controller isKindOfClass:[SampleViewController class]])
{
[[self navigationController] setNavigationBarHidden:YES animated:YES];
}
}
How to hide specific original navigation controller?
Thanks for all your help.
I was able to solve this.
Actually, I was pushing viewController to top one #1 navigationcontroller, whereas it was to pushed into bottom one #2 navigationcontroller.
And wrapping #2 navigationcontroller in a containerUIviewcontroller set right navigation.
Thanks

push view controller after dismissing presented view controller

I have this navigation stack
RootVC ---> VC1 --> (presenting)-> ModalVC
and I have VC2 (not in navigation stack).
When presenting ModalVC, I want to click on button in my ModalVC to dismiss ModalVC, then push VC2 into the navigation stack after VC1 at one click. It should look like this:
RootVC ---> VC1 ---> VC2
I tried a lot of methods to make it, but pushing event fire only, when I return to my RootVC.
I tried to make it with delegates:
In ModalVC on click:
[self dismissViewControllerAnimated:YES completion:^{
if ([self.delegate respondsToSelector:#selector(dismissAndPush:)]) {
[self.delegate performSelector:#selector(dismissAndPush:) withObject:VC2];
}
}];
In VC1:
- (void)dismissAndPush:(UIViewController *)vc {
[self.navigationController pushViewController:vc animated:NO];
}
Please help to understand this behavior. Where is my mistake?
From Apple Documentation:
The presenting view controller is responsible for dismissing the view
controller it presented.
So, VC1 should be dismissing the ModalVC, try to do this
ModalVC on click:
if ([self.delegate respondsToSelector:#selector(dismissAndPush:)]) {
[self.delegate performSelector:#selector(dismissAndPush:) withObject:VC2];
}
In VC1:
- (void)dismissAndPush:(UIViewController *)vc {
[self dismissViewControllerAnimated:YES completion:^{
[self.navigationController pushViewController:vc animated:NO];
}];
}
Error has been in other. If Im right understand: some animations before dismissing presented view controller are blocking animations in navigation stack. I solved this problem with 2 ways:
1) deleteting or set right animations before dismissing
2) use setViewControllers in navigation controller (I select it)
- (void)dismissAndPush:(UIViewController *)vc {
[self dismissViewControllerAnimated:NO completion:^{
NSMutableArray *mutableControllers = [NSMutableArray arrayWithArray:self.navigationController.viewControllers];
NSArray *controllers = [mutableControllers arrayByAddingObject:vc];
[self.navigationController setViewControllers:controllers animated:NO];
}];
}

PresentViewController hides Navigation bar in iOS

I am trying to show navigation controller when i present PresentViewController for navigate a screen. I solved this problem, but i faced another problem. Problem is when i push to a screen that time back button is visible on next screen with navigation controller. But when i am trying to PresentViewController, that time navigation bar is visible but not back button.
Here is my code:
- (IBAction)clickMeAction:(id)sender
{
ViewController1 *viewcontrol = [self.storyboard instantiateViewControllerWithIdentifier:#"ViewID"];
//[self.navigationController pushViewController:viewcontrol animated:YES]; // this is for push to viewcontroller
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:viewcontrol];
[self presentViewController:navigationController animated:YES completion:nil]; // This is for modalviewcontroller
}
Here is my output:
with push:
with modal:
Please help me.
Method 1:
[navigationController presentViewController:navigationController animated:YES completion:^{
[navigationController setNavigationBarHidden:YES animated:NO];
}];
Method 2: in presentViewController
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
self.navigationController.navigationBarHidden = YES;
}

How can a modal view controller be dismissed if the presenting view controller is changed?

I am presenting a modal view controller on the iPad which changes the presenting view controller while presented. For example:
A view controller VC presents the modal view controller when the user selects a cell in a table view.
The user selects an item on the modal view controller and another VC instance is opened in place of the first. Importantly, the view controller instance replacing the first is of the same type.
The modal view controller cannot be dismissed or an EXC_BAD_ACCESS exception occurs.
The failing dismiss is understandable: the presenting view controller is no longer available. Basically, how would I dismiss this presented modal view controller from a different presenting view controller?
The code I already have is:
ViewController1.m
- (void)showModalViewController:(UIViewController *)viewController
{
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:viewController];
navigationController.modalPresentationStyle = UIModalPresentationFormSheet;
viewController.navigationItem.rightBarButton = [[UIBarButton alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:#selector(dismissModalViewController)];
[self presentViewController:navigationController animated:YES completion:nil];
}
- (void)dismissModalViewController
{
[self dismissViewControllerAnimated:YES completion:nil];
[self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:YES];
}
Thanks for your suggestions but I solved the issue by using delegation. The presented view controller defined a delegate to notify the presenter when an action occurred.
ChildViewControler.h:
#protocol ChildViewControllerDelegate <NSObject>
- (void) childView:(ChildViewController *)childView didSelectItem:(Item *)item;
#end
ChildViewController.m:
// in interface
#property (nonatomic, weak) id <ChildViewControllerDelegate> delegate;
// in implementation
- (void)closeView:(Item *)anItem
{
[self.delegate childView:self didSelectItem:anItem];
}
ViewController1.m:
- (void)showModalViewController:(UIViewController *)viewController
{
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:viewController];
navigationController.modalPresentationStyle = UIModalPresentationFormSheet;
viewController.navigationItem.rightBarButton = [[UIBarButton alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:#selector(dismissModalViewController)];
// Different view controller types may be passed here so check is required...
if (viewController.class == [ChildViewController class]) {
((ChildViewController *)viewController).delegate = self;
[self presentViewController:navigationController animated:YES completion:nil];
}
- (void)childView:(ChildViewController *)childView didSelectItem:(Item *)item
{
[self dismissViewControllerAnimated:YES completion:nil];
[self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:YES];
// Perform action required with 'item'
}
You can try to change
self.presentingViewController
(The view controller that presented this view controller or its farthest ancestor.)
property in your modal View Controller before dismissing.
Here is your problem:
//...
viewController.navigationItem.rightBarButton = [[UIBarButton alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:#selector(dismissModalViewController)];
//...
- (void)dismissModalViewController
{
[self dismissViewControllerAnimated:YES completion:nil];
[self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:YES];
}
You try to dismiss presenter view controller (that is currently seems to be swithced to another already) instead of presented modal view controller (in your case it UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:viewController];)
so (if presenters view controllers not the tabs of tabViewController or not stored in navigationController's stack or somewhere else) you must to store reference to it somewhere else than in presenter view controller which will be switched and could be deallocated.
As per document presentingViewController is a readonly property.
You could not modify it.
#property(nonatomic,readonly) UIViewController *presentingViewController NS_AVAILABLE_IOS(5_0);
I have not tested this code but there may be error in dismissModalViewController.
please put break point on this method the first line is perfect may your second line may cause error,may self.tableView is not accessible or self.tableView indexPathForSelectedRow may be nil.
- (void)dismissModalViewController
{
[self dismissViewControllerAnimated:YES completion:nil];
[self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:YES];
}
Thanks.

Issue with definesPresentationContext / UIModalPresentationCurrentContext - Current context view controller gets lost

This only accours if you are presenting in a view controller that is managed by a navigation controller.
The reproduction steps are:
1 - Present a view controller using UIModalPresentationCurrentContext
self.definesPresentationContext = YES;
ViewController* viewController = [[ViewController alloc] init];
viewController.modalPresentationStyle = UIModalPresentationCurrentContext;
[presentOnViewController presentViewController:viewController animated:YES completion:nil];
2 - Present a view controller over the top using the default full screen presentation style
ViewController* viewController = [[ViewController alloc] init];
[self presentViewController:viewController animated:YES completion:nil];
3 - Dismiss the top presented view controller (the full screen one)
[self dismissViewControllerAnimated:YES completion:nil];
Now the problem is the 2nd view controller (presented using UIModalPresentationCurrentContext) disappears. Also it is impossible to present another view controller using UIModalPresentationCurrentContext, because the system thinks its still there.
I believe the issue is a bug in the framework. As mentioned it only occurs when the presenting in a view controller managed by a navigation controller. There is a nasty work around which uses the containment API. It creates a dummy view controller which views are presented from. The steps are:
1 - When presenting a view in context who's parent is a navigation controller, use a dummy view controller:
- (void)presentInContext
{
UIViewController* presentOnViewController = self;
if ([self.parentViewController isKindOfClass:[UINavigationController class]])
{
// Work around - Create an invisible view controller
presentOnViewController = [[DummyViewController alloc] init];
presentOnViewController.view.frame = self.view.frame;
// Containment API
[self addChildViewController:presentOnViewController];
[self.view addSubview:presentOnViewController.view];
[presentOnViewController didMoveToParentViewController:self];
presentOnViewController.definesPresentationContext = YES;
}
ViewController* viewController = [[ViewController alloc] init];
viewController.modalPresentationStyle = UIModalPresentationCurrentContext;
[presentOnViewController presentViewController:viewController animated:YES completion:nil];
}
2 - When dismissing the view controller tidy up
- (void)dismissSelf
{
__weak UIViewController* presentingViewController = self.presentingViewController;
[self dismissViewControllerAnimated:YES completion:^{
// Remove the dummy view controller
if ([presentingViewController isKindOfClass:[DummyViewController class]])
{
[presentingViewController willMoveToParentViewController:nil];
[presentingViewController.view removeFromSuperview];
[presentingViewController removeFromParentViewController];
}
}];
}
Thats it... The fix is dirty, but does the trick with no visual flicker.

Resources