Modal view controller over Presenting view controller - ios

I have a view controller that I am presenting modally over another view controller, and the background view for the top VC has a blur effect. When I am using the following code, the top view controller appears over the bottom view controller, but the top controller is hidden behind the navigation bar:
MOSettingsViewController *settingsViewController = [[MOSettingsViewController alloc]init];
settingsViewController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
settingsViewController.modalPresentationStyle = UIModalPresentationOverCurrentContext;
self.providesPresentationContextTransitionStyle = YES;
self.definesPresentationContext = YES;
[self presentViewController:settingsViewController animated:YES completion:nil];
When I remove the line settingsViewController.modalPresentationStyle..., the new view controller appears over the navigation bar, but the presenting view controller turns black, and ruins the blur effect.
How can I get a mixture of these two presentations, where the presenting view controller stays visible and the navigation bar is under the presented view controller?

Instead of using UIModalPresentationOverCurrentContext, I needed to use UIModalPresentationOverFullScreen.

Related

View controller is obscured when pushing a navigation controller

I have a navigation controller and a view controller inside of the navigation controller.
The view controller calls the navigation controller to push a view:
`MYVC *myvc = [MYVC new]`;
`[self.navigationController pushViewController:myvc
animated:YES]`;
Inside of MYVC I have the following logic for laying out my collection view:
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
_collectionView.frame = CGRectMake(0,
0,
self.view.frame.size.width,
self.view.frame.size.height - height);
}
This works fine for when I first load my vc as the collection view is loaded under my nav bar.
However when I push my vc it looks like the following:
Above the divider line is my nav bar and the red is my colleciton view.
It looks like the collection view is laid out under my navigation bar. If I drag on my collection view it lays out properly.
If I try changing the _collectionView frame's y position to
self.navigationController.navigationBar.frame.size.height however I get a large whitespace above my collection view after I drag on my collection view. How can I get it to be laid out properly the first time? Do I have to force layout? Is there some reason my nav bar isn't taken into account for the vc until I drag in the scroll view?

Popping UIViewController causes previous UIViewControllers View to change position

I have a UINavigationController with a UIViewController set as it's rootController, it contains a background on its UIView using an image set just under the navBar. I then push onto the navigation controller a new UIViewController and when the back button is pushed, the previous controller looks different. Using the visual debugger I can see that the self.view has moved entirely down below the navBar where previously it was at the top. I have no idea and been racking my brains as to why this might be happening
-(void)pushIPhoneMessagingContactsController:(MessageContactsViewController *)contactsController{
self.selectorView.hidden = YES;
[self.navigationController pushViewController:contactsController animated:YES];
}
On the RootViewController (iPhoneMessagingNotificationsController)
-(void)viewWillAppear:(BOOL)animated{
self.selectorView.hidden = NO;
[[[self navigationItem] leftBarButtonItem] setTintColor:[UIColor blackColor]];
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleDefault];
if ([_displayType intValue] == MESSAGES_SHOWING) {
[self.notificationsViewController.view removeFromSuperview];
[self.contentView addSubview:_messagesViewController.view];
} else {
[self.messagesViewController.view removeFromSuperview];
[self.contentView addSubview:_notificationsViewController.view];
}
}
It seems the offending line was in the viewWillAppear method of the pushed UIViewController
self.navigationController.navigationBar.translucent = YES;
Somewhere else this navigationBar gets set as translucent:
[self.navigationController.navigationBar setBackgroundImage:[UIImage new]
forBarMetrics:UIBarMetricsDefault];
self.navigationController.navigationBar.shadowImage = [UIImage new];
self.navigationController.navigationBar.translucent = YES;
and to make it solid colour again:
self.navigationController.navigationBar.shadowImage = nil;
self.navigationController.navigationBar.translucent = NO;
but this code seems to mess with the layout so perhaps there is another way to change the opacity of the navBar and statusBar without affecting the layout?
What you're currently trying to do is hide or show a selectorView which really only should appear for one specific view controller.
Here's an encapsulated way to solve this that makes your selectorView a part of the root view controller, removing the connection from other view controllers. They no longer have to know about it or hide it.
Add your selectorView to your rootViewController's navigation bar titleView. (You can do this in code, or drop it in Storyboard and add an IBOutlet for it.)
self.navigationItem.titleView = selectorView;
Now when you push another view controller, its title will replace your rootViewController's selectorView title (view). Your other view controllers don't need to know anything about that view.
This is a good design approach in general. Anytime you have a control that should only appear on one view controller's navigation bar, you want to make it a part of that view controller's navigationItem (titleView, or left/right bar button items.) iOS will display the control when it presents that view controller, and hide the control when that view controller is no longer the top view controller in the navigation controller stack.
As for the 64-pixel height issue, it's likely related to some complexity in the rootViewController hierarchy that shouldn't be there.
In iOS 7/8, a view's content, by default, appears under a translucent navigation bar. Apple freely managed this for you, by insetting the first view of the view hierarchy.
From your code, it appears that you're trying to "hide" or "show" the (un)selected viewController's view.
Each view controller should have a view it controls. A view controller shouldn't be trying to control other view controller's views, or adding other view controller's views to its own view hierarchy.
Here's Apple's recommended way to approach this. Use a containerView in your rootViewController. The whole purpose of a container view is to encapsulate a view controller within a view. As your selectorView changes which view to show, you have your container view transition from one view controller to the other. (If you're not familiar with how to do that, check out this answer.)
Pin the containerView to the rootViewController's view, so Auto Layout can size it for you.
Your view hierarchy now looks like view -> containerView, instead of view -> hidden view of unselected view controller, shown view of selected view controller. Apple can adjust the first view's inset, and nothing gets incorrectly offset (by the height of the navigation control).
Update:
This question talks about scrollViewInsets and how they can be set on a view-controller-by-view-controller basis. If you do have a view controller, and you don't want its content to appear under a bar, uncheck that box.
But the best way to handle this is to "standardize" your UI, so it isn't varying from view to view. Either make the bar always be translucent, or not always be translucent. This makes transitions less "jarring" for the users.

How to present modal view controller with transparent background

I working with swift and how to how to present modal view controller but his background to be transparent. Content of other view controller to be visible in back.
This one works for me :
self.presentingViewController.providesPresentationContextTransitionStyle = YES;
self.presentingViewController.definesPresentationContext = YES;
modal.modalPresentationStyle = UIModalPresentationOverCurrentContext;

alternating between toolbar / tab bar

my app is structured as follow: UITabBarController > UINavigationController > ViewControllerOne > ViewControllerTwo.
the UINavigationBar has at the bottom the tab bar, now when the user navigates into the second view controller, i want to be able to hide the tab bar and replace is with a tool bar. i tried this code:
[self.navigationController.tabBarController.tabBar setHidden:YES];
[self.navigationController.toolbar setHidden:NO];
when i run the app the tab bar is hidden but the toolbar doesn't appear. plus, since the last VC is a table view controller, when i scroll through the cells there is a white gap between the table and the bottom of the view. how can i fix that?
That won't work because when you hide the tab bar like that the subviews won't be adjusted properly (that's why you get the white space). You'll have to use
self.hidesBottomBarWhenPushed = YES;
In your init method or awakeFromNib... and then
[self.navigationController setToolbarHidden:NO animated:YES];
In the viewDidLoad for example.
That way the tab bar controller's view is going to layout correctly it's subviews when you hide the tab bar. Just remember to call self.hidesBottomBarWhenPushed = NO; in your first view controller otherwise the tab bar is still going to be hidden when the second view controller is popped from the navigation stack.
Try to assigning toolbar with appropriate frame and adding it to self.tabBarController.view

UIViewController Present

I am trying to present a UIViewController with a UIView on it.
The following is the code I am trying in my viewDidLoad method.
//create the view controller
UIViewController *controller = [[UIViewController alloc] init];
UIView *view = [[UIView alloc] init];
view.backgroundColor = [UIColor whiteColor];
controller.view = view;
//show the view
[self presentViewController:controller animated:YES completion:nil];
When I run the app, it is giving me the following error.
Warning: Attempt to present <UIViewController: 0x751fcd0> on <ViewController: 0x751d7a0> whose view is not in the window hierarchy!
What does this mean and where am I going wrong? Shouldn't it display a white view or am I understanding wrong?
Thanks.
The solution is to move my code to the viewDidAppear method.
I'm assuming that the view controller's view is not in the window hierarchy at the point that it has been loaded (when the viewDidLoad message is sent), but it is in the window hierarchy after it has been presented (when the viewDidAppear: message is sent).
If you call presentViewController:animated:completion from 'viewDidLoad:' it won't work. And that is why:
The area of the screen used to define the presentation area is determined by the presentation context. By default, the presentation context is provided by the root view controller, whose frame is used to define the frame of the presentation context. However, the presenting view controller, or any other ancestor in the view controller hierarchy, can choose to provide the presentation context instead. In that case, when another view controller provides the presentation context, its frame is used instead to determine the frame of the presented view. This flexibility allows you to limit the modal presentation to a smaller portion of the screen, leaving other content visible.
View Controller Programming Guide for iOS: Presenting View Controllers from Other View Controllers
In viewDidLoad frame of presenting view controller simply not set yet. That is why you should present next controller only when presenting controller is on screen.

Resources