Modal View using UIModalPresentationFormSheet appears offscreen - ipad

I have a UIViewController that implements
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
Then, I try to popup a modal on top of that view:
ModalViewController *modalViewController = [[ModalViewController alloc] init];
modalViewController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
modalViewController.modalPresentationStyle = UIModalPresentationFormSheet;
[mainViewController presentModalViewController:modalViewController animated:YES];
If I launch the modal while the ipad is in portrait, it works fine. But when I'm holding it in landscape and try to launch the modal, the modal appears half offscreen to the upper right of the ipad. Any ideas?

In ModalViewController, implement shouldAutorotateToInterfaceOrientation the same way that it is in mainViewController (both need to agree on the orientations they support).

Related

Black Screen After Dismissing Modal Controller

I've discovered that after dismissing a modal view controller that's presented fullscreen in a compact view and as a popover in a horizontally regular view, the screen goes black after the animation.
My View Hierarchy is the following
View (of my rootViewController on the window)
--->UISplitViewController.view ( set as a child viewController )
--------> rootViewController.view (set as the mainViewController of the splitView)
--------> detailViewController.view (set as the detailViewController of the split view)
Via the iPhone 6 simulator(split view is always collapsed) I present a modal viewcontroller with the following code:
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:viewController];
[navigationController.navigationBar setBarStyle:UIBarStyleBlack];
[navigationController setModalPresentationStyle:UIModalPresentationPopover];
navigationController.popoverPresentationController.sourceView = view;
navigationController.popoverPresentationController.barButtonItem = barButtonItem;
navigationController.popoverPresentationController.delegate = self;
[self presentViewController:nav animated:YES completion:nil];
I dissmiss the presented controller from that viewController by calling:
[self dismissViewControllerAnimated:true completion:nil];
If I set animated to "false" I dont have any problems, but it looks bad and doesnt make sense.
I see some posts regarding this and custom presenatation methods, but I'm not using anything custom here.
On iPhone the ModalPresentationStyle should default to UIModalPresentationOverFullScreen, so I tried setting the presentationStyle directly to that, and it worked!
If I set the presentationStyle to "FullScreen" (not over fullscreen) I get the same behavior, a black screen after dismissing.
Any thoughts or experiences on this one?
I've come up with the following work around, but I still don't think it should be needed.
- (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller traitCollection:(UITraitCollection *)traitCollection{
if( traitCollection.horizontalSizeClass == UIUserInterfaceSizeClassCompact )
{
return UIModalPresentationOverFullScreen;
}
else
{
return UIModalPresentationPopover;
}
}

Difference UI for portrait and landscape ipad

I would like to create an application like this:
On iphone (both portrait and landscape) and ipad portrait, I have a table view screen, tap on item row will navigate to another detail screen look like other basic application.
But when I rotate screen to go to landscape on ipad, the screen now has two section views
Here is what I did:
Write a method isInLandscapeTablet to detect ipad landscape
Use UINavigationController as a root controller to control all other views
In portrait screen, push a viewcontroller contains tableview to root controller
In landscape tablet screen, attach tableview controller and detail controller to UISplitViewController, then push it into root controller
But the problem is I can't push UISplitViewController to root controller, as it requires to be a root controller.
I wonder how I can handle this problem
And is my approach correct? Is there any other way?
Update: I change the root view controller like this
// this snippet is in UINavigationController (I use as root viewcontroller)
if([self isInTabletLandscape]){
self.splitViewController.viewControllers = [NSArray arrayWithObjects:[[CategoryViewController alloc] initWithNibName:#"CategoryViewController" bundle:nil], self.propertyLandViewController, nil];
[[UIApplication sharedApplication].keyWindow setRootViewController:self.splitViewController];
}else{
// it doesn't work
[[UIApplication sharedApplication].keyWindow setRootViewController:self];
}
}
After knowing the device whether it is iPad or iPhone. You Can try to remove the RootViewController.
appDelegate.window.rootViewController = nil;
Then you set the root view controller with a new SplitViewContloller
id objClass =[[SplitViewController alloc]initWithNibName:#"SplitViewController" bundle:nil];
masterVC.delegate = detailVC;
detailVC.delegate = objClass;
[objClass setViewControllers:#[masterNavigate,detailNavigate]];
[appDelegate.window setRootViewController:objClass];
My suggestion is not to use Split View Controller at all. Create a custom View Controller, which will embed your table view controller and the 2nd controller. Also, you can implement the interface-rotation logic in the custom controller you create.
If you are developing on iOS 8 you should use Size Classes, so you can totally change the layout depending on iPhone/iPad portrait and iPad Landscape. Unfortunately on iOS 7, size classes only differentiate iPhone and iPad.
In both case the right part (2), can be easily handle with a containerView.
https://developer.apple.com/library/ios/documentation/WindowsViews/Conceptual/ViewControllerCatalog/Chapters/SplitViewControllers.html
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
MyFirstViewController* firstVC = [[MyFirstViewController alloc] init];
MySecondViewController* secondVC = [[MySecondViewController alloc] init];
if ( ([[UIDevice currentDevice] orientation] == UIDeviceOrientationPortrait) ){
UISplitViewController* splitVC = [[UISplitViewController alloc] init];
splitVC.viewControllers = [NSArray arrayWithObjects:firstVC, secondVC, nil];
window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
window.rootViewController = splitVC;
[window makeKeyAndVisible];
}
else
{
// Display tableview
}
return YES;
}
I assume this may help you..

Disable UITableViewcontroller from rotating in Landscape (keep it Portrait orientation)

I'm trying to keep UITableViewcontroller in Portrait orientation. Hence, I don't want to rotate to Landscape mode. I added below method. But it didn't help, notice I'm using iOS 8:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
if(interfaceOrientation== UIInterfaceOrientationPortrait)
{
return YES;
}else
{
return NO;
}
}
Notice, I'm calling the UITableView through UINavigationController
UINavigationController *navigationController = [[UINavigationController alloc]
initWithRootViewController:svc];
// configure the new view controller explicitly here.
[self presentViewController:navigationController animated:YES completion: nil];
You can set the enabled orientation interface in the Info.plist or, if you want only the Table in this way, you have to modify manually the supportInterfaceOrientation in the navigationController when you are presenting the view. The 'child' will assume the values from the navigationController. Then, when you dismiss the table, you have to reset the supportInterfaceOrientation manually.

Orientation Landscape -> Portrait isn't working

I have another orientation problem. But this one is very tricky.
My RootViewController is a normal NavigationController.
self.window.rootViewController = _naviController;
which has another ViewController inside, lets call it VC1.
VC1 has some buttons and labels. Its like an overview with folders.
If I press a button I come to the next ViewController with 3 ViewController (Page) and another bunch of buttons (like inside a folder looking at the pictures/thumbnails inside):
Archiv *archiv = [[Archiv alloc] init];
[self.navigationController pushViewController:archiv animated:YES];
[archiv release];
in loadView:
firstPage = [[Page alloc] initViewWithFrame:CGRectMake(0, 0, 768, 960)];
[firstPage setRootViewController:self];
secondPage = [[Page alloc] initViewWithFrame:CGRectMake(0, -960, 768, 960)];
[secondPage setRootViewController:self];
thirdPage = [[Page alloc] initViewWithFrame:CGRectMake(0, 960, 768, 960)];
[thirdPage setRootViewController:self];
If I now click again on a button the active Page push my third ViewController (image with resizing, dragging...):
Picture *pic = [[Picture alloc] initWithPicURLString:urlString];
[rootViewController.navigationController pushViewController:pic animated:YES];
[pic release];
With the BackButton of the NavigationController I can always come back to the previous view.
Some more informations:
Every ViewController supports all orientations
Every ViewController implements - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation with return YES;
Every ViewControler calls the [super init] in their init-methode
I already read Apple's Q&A: Why won't my UIViewController rotate with the device
Now the tricky problem:
If I switch from 2nd VC to the 3rd VC, change the orientation there from portrait to landscape and press the BackButton everything is working (shouldAutorotateToInterfaceOrientation is calling, frame size and origins changing ...).
BUT if I do it the other way around, I am in landscape mode, switch from 2nd VC to 3rd VC, rotate to portrait and come back to 2nd VC with BackButton, the status- and controllerBar are at the top but the shouldAutorotateToInterfaceOrientation wasn't called.
Please help me. $h#rky
Try this, it works for me:
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self shouldAutorotateToInterfaceOrientation:[[UIApplication sharedApplication] statusBarOrientation] ];
}
Today I got the idea that solved the problem without knowing the cause.
In my third VC I just created a pointer to the 2nd View and called the shouldAutorotateToInterfaceOrientation myself.
But the point is still the same: Why isn't shouldAutorotateToInterfaceOrientation not calling in the described situation?
Kind regards. $h#rky
shouldAutorotateToInterfaceOrientation only called when user rotate, so when you from landscape to portrait or otherwise then view controller still landscape, so this solve problem, you have to hack code, it's mean when you push to view controller from landscape to portrait presentViewController example:
ListCurrentViewController *list = [self.storyboard
instantiateViewControllerWithIdentifier:#"ListCurrentViewController"];
[self.navigationController presentViewController:list animated:NO completion:Nil];
[list dismissViewControllerAnimated:NO completion:Nil];
[self.navigationController pushViewController:list animated:YES];
in ListViewController function called:
(UIInterfaceOrientation)preferredInterfaceOrientationForPresentation // iOS 6 autorotation fix { return UIInterfaceOrientationPortrait; }
and you have to create category for UINavigationController
(UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return [self.visibleViewController preferredInterfaceOrientationForPresentation];
}
I hope this solve will help you.

Ipad: SplitViewController black DetailViewController

i have the following problem.
I'm developing an app with a splitViewController as the root controller. In the appDelegate i have this code in method didFinishLaunchingWithOptions:
[self.window addSubview:splitViewController.view];
[self.window makeKeyAndVisible];
self.sendData = [[[SendData alloc] init] autorelease];
showEventsViewController.sendData = self.sendData;
LoginView *lvc = [[LoginView alloc] initWithNibName:#"LoginView" bundle:nil];
lvc.delegate = self;
[splitViewController presentModalViewController:lvc animated:NO];
[lvc release];
return YES;
When the login is complete, i dismiss the loginView and i show the splitViwController.
Besides, my application needs to run only in landscape mode, so i have configured the plist in order to avoid only landscape mode and set this code in each view controller:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Overriden to allow any orientation.
if (interfaceOrientation == UIInterfaceOrientationLandscapeLeft)
return YES;
if (interfaceOrientation == UIInterfaceOrientationLandscapeRight)
return YES;
return NO;
}
But when i run my app in portrait mode (the login view is shown right in landscape) and icomplete the login, the splitview is shown in landscape mode but the detailViewController is whole black (the master view is in landscape mode)
What is happening?
Thanks

Resources