I've created a project from the master detail template in Xcode 4.2/iOS5. I am trying to preform a modal segue from the splitviewcontroller. I call the following from my detailviewcontroller.m:
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self.splitViewController performSegueWithIdentifier:#"DisplayLoginView" sender:self.splitViewController];
}
The login view shows fine but it does not rotate and stays in portrait. Any ideas on how to get it to autorotate?
I fixed this by implementing a custom class for the destination view controller and adding the
shouldAutorotateToInterfaceOrientation: method making sure it returned YES.
Related
I'm attempting a project using the Xcode (version 9.1 9B55) Master-Detail template, using one Storyboard for both iPhone and iPad.
I want to use the built in popover segue, which ideally will show a popover when the size class is appropriate, or a modal view controller when the size class is compact (iPhone in portrait).
What I am finding is that it works just fine for iPad, but when I run it on an iPhone, you can't touch outside the popover to dismiss as I would expect.
When on iPad, popoverPresentationControllerDidDismissPopover is called and all is well.
When on iPhone, the popoverPresentationControllerDidDismissPopover never gets called and you cannot dismiss the popover.
To reproduce, I did this:
Create new Master-Detail App
New - File. Cocoa Touch Class, called MyPopoverViewController
In Storyboard:
Create new view controller, change class to MyPopoverViewController.
On MasterViewController, add bar button item "Popover". Control-drag from this to MyPopoverViewController. Set segue Kind to "Present As Popover". Set Identifier to "thePopover".
In MasterViewController.h, add UIPopoverPresentationControllerDelegate:
#interface MasterViewController : UITableViewController <UIPopoverPresentationControllerDelegate>
In MasterViewController.m:
#import "MyPopoverViewController.h"
In viewDidLoad, comment out two lines which create the "Add Button".
In prepareForSegue:
} else if ([[segue identifier] isEqualToString:#"thePopover"]) {
NSLog(#"MVC prepareForSegue thePopover");
MyPopoverViewController *myPopoverController = segue.destinationViewController;
myPopoverController.popoverPresentationController.delegate = self;
}
Add three UIPopoverPresentationControllerDelegate delegate methods:
- (void) prepareForPopoverPresentation:(UIPopoverPresentationController *)popoverPresentationController {
NSLog(#"MVC prepareForPopoverPresentation");
}
- (void) popoverPresentationControllerDidDismissPopover:(UIPopoverPresentationController *)popoverPresentationController {
NSLog(#"MVC popoverPresentationControllerDidDismissPopover");
}
- (BOOL) popoverPresentationControllerShouldDismissPopover:(UIPopoverPresentationController *)popoverPresentationController {
NSLog(#"MVC popoverPresentationControllerShouldDismissPopover");
return TRUE;
}
I tried this also, but all it does is force popover in portrait mode (which I don't want); doesn't change the lack of popover delegate calls and doesn't allow us to dismiss popover:
-(UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller {
return UIModalPresentationNone;
}
I'm hoping there is something simple I'm missing here. I have uploaded a sample project here, which is exactly what I've described above:
https://github.com/johnstewart/MasterDetailPopoverTestProject
How do I allow iPhone to also dismiss popovers by touching outside the popover?
If I understand your question correctly your problem appears on iPhone 8 Plus in landscape mode.
In this situation, the presented popover actually is not a popover but a normal presented view. Visually it looks like a sheet that appears from the botton of the screen. In order to close such a view, you have to add your own button to do this.
If you want to show a real popover, you must implement:
adaptivePresentationStyleForPresentationController:traitCollection:
to return UIModalPresentationNone. Note the additional parameter traitcollection:. UIAdaptivePresentationControllerDelegate contains two similar methods. In your project you already implemented the method:
adaptivePresentationStyleForPresentationController:
Change this to the former method and everything should work.
I have an iOS 7 app with a side hamburger menu and a main table view controller where I display content. Whenever the user selects an item in my side menu, I'm hiding the side menu and I want to reload data in the main view controller. My initial thought was to put my data refreshing code in my main view controller's viewWillAppear:
But when I set a breakpoint in viewWillAppear:, I get 2 calls when the view controller initially appears, one from UIViewController itself, and another from [ECSlidingViewController viewWillAppear:] where the following line seems to call my viewWillAppear: again
[self.topViewController beginAppearanceTransition:YES animated:animated];
On the other hand, when I show the left menu and then hide it, my view controller's viewWillAppear: is not called this time, so data is not refreshed in my case.
Did I miss something in my configuration somewhere? Is that a bug or a feature? How should I use it?
PS: I used to use IIViewDeckController and I had the exact same problem, so I switched to ECSlidingViewController because it said that "Your view controllers will receive the appropriate view life cycle and rotation methods at the right time.".
As a matter of fact, I managed to do what I wanted with another library: https://github.com/romaonthego/RESideMenu
I had to implement delegate methods in order to call lifecycle methods on my view controller when menu is shown or hidden:
- (void)sideMenu:(RESideMenu *)sideMenu willShowMenuViewController:(UIViewController *)menuViewController {
[sideMenu.contentViewController viewWillDisappear:YES];
}
- (void)sideMenu:(RESideMenu *)sideMenu didShowMenuViewController:(UIViewController *)menuViewController {
[sideMenu.contentViewController viewDidDisappear:YES];
}
- (void)sideMenu:(RESideMenu *)sideMenu willHideMenuViewController:(UIViewController *)menuViewController {
[sideMenu.contentViewController viewWillAppear:YES];
}
- (void)sideMenu:(RESideMenu *)sideMenu didHideMenuViewController:(UIViewController *)menuViewController {
[sideMenu.contentViewController viewDidAppear:YES];
}
And viewWillAppear is not called twice initially.
I have a problem with an app I am working on that goes like this:
The app's window has a rootViewController which is set to a custom class (MenuViewController) of UIViewController. This view controller has a rootViewController property of it's own. Whenever set this happens (really short version of the code):
- (void)setRootViewController:(UIViewControlelr *)rootViewController
{
...
_rootViewController = rootViewController;
if (self.rootViewController) {
[self addChildViewController:rootViewController];
[self.view addSubview:rootViewController.view];
}
...
}
Now this MenuViewController can show a modal view controller on top of it's rootViewController.
I do that like this:
[self.rootViewController presentModalViewController:viewController animated:YES completition:nil];
Everything looks to be ok until here. Now on iPad whenever I call [self.presentingViewController dismissViewControllerAnimated:YES completion:nil] from my modal view controller the interface beneath it rotates to the same orientation (that is UIInterfaceOrientationLandscapeLeft) regardless of what the initial orientation was when the view controller was presented.
So to conclude, my view's hierarchy is this:
Window
|
- Menu View Controller
|
- Root View Controller
|
- Modal view controller
Does anyone know how I can fix this? It doesn't happen on the iPhone.
It sounds to me as though on the iPad your MenuViewController's rootViewController supports multiple interface orientations, whereas on the iPhone it does not. This is speculation, as you have not said anything about this.
If this is the case, and the rootViewController does indeed support multiple interface orientations, the fix would be to override - supportedInterfaceOrientations and return portrait, which seems to be what you are suggesting you would want.
I have an iOS application using storyboards where I display a view controller that I create from an .xib file to the user. This view controller accepts some user input, but I then have to dismiss it and return to the main application. I am able to display the view controller, which also has a button that calls a method to dismiss the view controller. My problem is that after the user presses the button to go back to the main application, the entire screen goes black. Here is my code for the button from the .xib view controller that is trying to remove itself from the display:
- (IBAction)myButtonAction:(id)sender {
[self.view removeFromSuperview];
}
Here is the code from my main application's view controller which calls the .xib view Controller in the first place:
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
_nextView = [[NextLandscapeViewController alloc] initWithNibName:#"NextLandscapeViewController" bundle:nil];
[_nextView setDelegate:(id)self];
NextNavigationController *navigationController = [[NextNavigationController alloc] initWithRootViewController:_nextView];
[self presentViewController:navigationController animated:YES completion:nil];
}
NextNavigationController is a subclass of UINavigationController which I do for the purpose of loading _nextView in landscape mode instead of portrait mode. This part is working fine. My concern now is dismissing this viewController after the user is finished working with it, and return back to the calling view controller in the main application.
Is there any reason why my screen is black? How I can resolve this issue?
Don't use removeFromSuperview, use [self dismissViewControllerAnimated:YES completion:nil]; Just like you use a pop to undo a push, you use dismissViewController to undo a presentViewController. The reason you get a black screen is because presenting a view controller removes the view of the presenting view controller from the window's hierarchy. So, when you remove the view from the superview, there's nothing underneath but the window.
I am trying to implement a hide/unhide feature for the master view controller of my UISplitViewController. So the master view controller should be present in portrait and landscape mode but just for a specific view (the settings). Everywhere else it should appear in landscape only.
In -(void)viewDidAppear:(BOOL)animated of my MasterController I am writing
self.popoverController.delegate = self;
appDelegate.splitViewController.delegate= nil;
appDelegate.splitViewController.delegate = self;
[appDelegate.splitViewController willRotateToInterfaceOrientation:self.interfaceOrientation duration:0];
[appDelegate.splitViewController didRotateFromInterfaceOrientation:self.interfaceOrientation];
appDelegate.splitViewController.view setNeedsLayout];
The delegate method is also set
- (BOOL)splitViewController:(UISplitViewController *)svc shouldHideViewController:(UIViewController *)vc inOrientation:(UIInterfaceOrientation)orientation
{
return NO;
}
This approach I found here on stackoverflow really works well, but just as long as I rotate the device. Then the master view controller disappears (and leaves a black space). While rotating it appears and as soon as the rotation is done it disappears again. Further the master view controller disappears complelty if I click outside.
So I implemented the following delegate method to prevent the popover from disappearing
- (BOOL)popoverControllerShouldDismissPopover:(UIPopoverController *)popoverController
{
return NO;
}
That works too, but then the tableView of my detail view is not responding.
If I delete the code from -(void)viewDidAppear:(BOOL)animated and the UIPopoverControllerDelegate method, it works all as expected, but just after I rotate the device.
So my question is, if anyone has an idea how I can solve that problem. The solution should be able to work with iOS 5.0 and newer.
Thanks a lot for your answers!