iPad UISplitViewController rotates unnecessarily when modal dialog is closed - ipad

I have a reasonably simple split view application adapted from iPhone code. The main functionality is in shared classes with iPhone and iPad specific classes inheriting and augmenting the code. All the classes used in the iPad app have the following:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Overriden to allow any orientation.
return YES;
}
The main view controller consists of a UIToolbar and a UITableView. The responds to rotations correctly at every stage bar two. If I present a modal dialog from this view:
navigationController = [[UINavigationController alloc] initWithRootViewController:tvc];
navigationController.modalPresentationStyle = UIModalPresentationFormSheet;
[self presentModalViewController:navigationController animated:NO];
Everything works as expected including rotating the device until I dismiss the dialog in any way with:
[self dismissModalViewControllerAnimated:YES];
At which point my main view rotates 90 degrees. I've looked into the settings in nib files and it all seems to be fine. Any advice? A modal dialog presented by the UITableView on the left hand side does not present this problem.
Bonus Question:
I've discovered the modal dialog presented by the left hand view does have a glitch. But only one. If it is presented by the popover view in portrait mode and the device is rotated you get a rather impressive graphical glitch as it rotates out of the view for ever!

As noted in the comment above I managed to merge the two view controllers into one, incorporating the code to handle the toolbar + splitview controller into the iPad version. Originally there was a common class which inherited from UITableViewController, both the iPad and iPhone versions of the code inherited from this common class.
The problem was on the iPad I wanted a toolbar at the top and had to support the splitview controller too. This was problematic given that the class was a UITableViewController so I created a parent class containing the toolbar and the tableview controller plus the splitview code.
In refactoring I changed the common class to a UIViewController and made the changes to support a UITableView in code, as normal and instructed in several iPhone dev books. In the iPhone version of class I manually create the UITableView with the necessary methods. In the iPad version it comes from a xib file.
This schematically simplifies things as now the main view doesn't have a controller within a controller. It also solves the problem. The UI rotating 90 degrees upon closing a modal dialog no longer occurs.

Related

What is the large popup view in UIKit called?

I am writing an iPhone application where I want to utilize the large popup view, but I don't know what it's called. I have a picure on it.
I mean the middle square that isn't shadowed. It has the title "Köp mer utrymme". I know it's from an iPad, but I'm pretty sure a similiar one exists on the iPhone, for example, the iTunes-store agreements. I looked in Apple's UIKit User Interface Catalog, but I couldn't found it there.
Does anyone know what it's called or how to get it?
On iPad it could be a UIPopoverController with a custom view controller inside it, or a modally presented view controller. You can't use that on iPhone (at least not in the same way, popovers don't exist and modal views are full screen).
On iPhone you could use a UIAlertView, or you could search github / cocoacontrols for a suitable 3rd party implementation.
The view on the picture is presented modally. When presenting a view modally, you can customize the presentstion style. The default style is UIModalPresentationFullscreen, but the style in the picture is UIModalPresentationFormSheet.
To present a view controller in that style, you first create an instance of the view controller and then set its style.
MyViewController *vc = [[MyViewController alloc] init];
vc.modalPresentationStyle = UIModalPresentationFormSheet;
[self presentViewController:vc animated:YES completion:nil];
Note that isn't possible to change the presentation style for iPhone. (I must have imagined that the iTunes-store agreement wasn't fullscreen.)
Use KGModal.h and KGModal.m class. For a PopVieController is is best ....and easy to make and add control over it and no need to set frame for orientation ....
Find these 2 Class (KGModal.h and KGModal.m)...

presentViewController working in iOS 6 but not displaying the view in iOS 5

I started developing my app for iOS 6 and got it working there, now I am having to make sure it also supports iOS 5.1 so it will work on the iPad 1. The port was pretty easy, though only supporting landscape orientation is more of a pain in iOS 5 compared to how easy it is in 6. I'm left with one issue that I can't resolve.
I have the starting screen layout shown below and then when you press the 'Perform' button it should present another view controller modally, full screen. This is the code that the perform button calls in the parent view controller.
- (void)performButtonPressed:(UIImage *)notationImage {
self.performViewController = [[YHPerformViewController alloc] initWithImage:notationImage
recordingService:self.performanceRecordingService];
self.performViewController.modalPresentationStyle = UIModalPresentationFullScreen;
self.performViewController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentViewController:self.performViewController animated:YES completion:^{
[self.performViewController startPerformance];
}];
}
In iOS 6 this is fine. In iOS 5 all the right code seems to be called:
loadView on the view controller being presented
shouldAutorotateToInterfaceOrientation - to which I return YES
my 'startPerformance' method is called and does its things
However the view doesn't actually appear on screen and all the views associated with view controllers higher up the hierarchy stay on screen (the shapes at the top and the navigation control). Only the view for the current view controller is faded out. Even weirder is that during the transition this view is rotated 90 degrees as it is fading out. I've included a screen capture below. If I change the modalPresentationStyle to UIModalPresentationFormSheet it kind of works apart from the expected issue of my full sized view not fitting.
Any thoughts?
Starting layout:
Weird rotation of subview during transition. Also the whole screen should be fading out, not just one view:
What was expected to happen and does in iOS 6.
I have come up with a hack that solves this problem. But I would love to find a real solution.
My bodged solution is to change the modalPresentationStyle to UIModalPresentationFormSheet. Then use a variation on the hack described in How to resize a UIModalPresentationFormSheet? to get the form sheet to be the desired size.
- (void)performButtonPressed:(UIImage *)notationImage {
self.performViewController = [[YHPerformViewController alloc] initWithImage:notationImage
recordingService:self.performanceRecordingService];
// This is a bit of a hack. We really want a full screen presentation, but this isn't working under iOS 5.
// Therefore we are using a form sheet presentation and then forcing it to the right size.
self.performViewController.modalPresentationStyle = UIModalPresentationFormSheet;
self.performViewController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentViewController:self.performViewController animated:YES completion:^{
[self.performViewController startPerformance];
}];
self.performViewController.view.superview.bounds = self.performViewController.preferredBounds;
}
This requires the view controller being presented to a 'preferredBounds' property and to have this in its loadView method.
- (void)loadView {
… // Usual loadView contents
// Part of the hack to have this view display sized correctly when it is presented as a form sheet
self.preferredBounds = self.view.bounds;
}
[self presentViewController:self.performViewController animated:YES completion:nil] works in iOS 6+ versions only.
You have to use [self presentModalViewController:controller animated:YES]; in

XCode: MasterDetailsView - DetailsView without Splitscreen in Landscape?

actually I'm quite new with Xcode and couldn't find the answer to the following two questions by a google search:
to make it short: I'm working on an iPad app that displays proposals. For this purpose you should choose a proposal from the table in MasterView and then see the details in the DetailsView in landscape mode (but without the MasterView on the Spitscreen).
So when the app starts in landscape mode, I wanna see directly the first proposal full screen on the DetailsView. And when I tap onto the screen the MasterView should popup/unhide with the other proposals in the table. Is this possible?
I wanna display the PDFs in a WebView like in iBooks. That means that the navigation bar is hidden and only when I tap onto the screen the navigation bar should appear at the top of the screen.
I'm kind of sure this questions have been solved somewhere but I couldn't find anything by search so I hope you can help me anyway :-)
Thanks in Advance!
Q1: Use can use one of many methods to present a view (look up under Apple's doc on UIViewController under "Presenting Another View Controller's Content" heading). Two that I have used are: – presentModalViewController:animated: and – presentViewController:animated:completion: (the latter is the latest addition in iOS 5.0)
So let's say you have a detail controller called MyDetailViewController, in your Master View Controller's implementation file (the .m file), under viewDidLoad method, you would do some thing like this to present it as a full screen view.
MyDetailViewController *myDetailViewController = [[MyDetailViewController alloc] initWithNibName:#"MyDetailViewController" bundle:nil];
[myDetailViewController.view setFrame:CGRectMake(0, 0, 1024, 768)]; //might not need this
[self presentViewController:newDetailViewController animated:YES completion:^{
NSLog(#"complete"); //optional
} ];
To dismiss or hide this MyDetailViewController with a tap or touch, you can use UITapGestureRecognizer or touchesEnded method and using one of the dismiss methods (refer back to Apple's UIViewController again for this).
Q2: I personally have not used UIWebView to display PDF and not sure if iBooks is using UIWebview to do it. But to display a varieties of popular documents formats, you can use either the QLPreviewController class or UIDocumentInteractionController. You can hide the toolbar while the document is displayed.
Good luck.

iOS5 breaks UISplitViewController rotation callbacks, how to invoke manually?

As has been reported in other questions here on SO, iOS 5 changes how rotation callbacks for split view controllers are sent as per this release note. This is not a dupe (I think), as I can't find another question on SO that deals with how to adjust split view controller usage in iOS 5 to cope with the change:
Rotation callbacks in iOS 5 are not applied to view controllers that
are presented over a full screen. What this means is that if your code
presents a view controller over another view controller, and then the
user subsequently rotates the device to a different orientation, upon
dismissal, the underlying controller (i.e. presenting controller) will
not receive any rotation callbacks. Note however that the presenting
controller will receive a viewWillLayoutSubviews call when it is
redisplayed, and the interfaceOrientation property can be queried from
this method and used to lay out the controller correctly.
I'm having trouble configuring the popover button in my root split view controller (the one that is supposed to show the left pane view in a popover when you're in portrait). Here's how my app startup sequence used to work in iOS 4.x when the device is in landscape mode:
Install split view controller into window with [window addSubview:splitViewController.view]; [window makeKeyAndVisible];. This results in splitViewController:willHideViewController:withBarButtonItem:forPopoverController: being called on the delegate (i.e. simulating a landscape -> portrait rotation) even though the device is already in landscape mode.
Present a fullscreen modal (my loading screen) which completely covers the split view underneath.
Finish loading and dismiss the loading screen modal. Since the device is in landscape mode, as the split view controller is revealed, this causes splitViewController:willShowViewController:invalidatingBarButtonItem: to be called on the delegate (i.e. simulating a portrait -> landscape rotation), thereby invalidating the bar button item, removing it from the right-side of the split view, and leaving us where we want to be. Hooray!
So, the problem is that because of the change described in that release note, whatever happens internally in iOS 4.3 that results in splitViewController:willShowViewController:invalidatingBarButtonItem: being called no longer happens in iOS 5. I tried subclassing UISplitViewController so I could provide a custom implementation of viewWillLayoutSubviews as suggested by the release note, but I don't know how to reproduce the desired sequence of internal events that iOS 4 triggers. I tried this:
- (void) viewWillLayoutSubviews
{
[super viewWillLayoutSubviews];
UINavigationController *rightStack = [[self viewControllers] objectAtIndex:1];
UIViewController *rightRoot = [[rightStack viewControllers] objectAtIndex:0];
BOOL rightRootHasButton = ... // determine if bar button item for portrait mode is there
// iOS 4 never goes inside this 'if' branch
if (UIInterfaceOrientationIsLandscape( [self interfaceOrientation] ) &&
rightRootHasButton)
{
// Manually invoke the delegate method to hide the popover bar button item
[self.delegate splitViewController:self
willShowViewController:[[self viewControllers] objectAtIndex:0]
invalidatingBarButtonItem:rightRoot.navigationItem.leftBarButtonItem];
}
}
This mostly works, but not 100%. The problem is that invoking the delegate method yourself doesn't actually invalidate the bar button item, so the first time you rotate to portrait, the system thinks the bar button item is still installed properly and doesn't try to reinstall it. It's only after you rotate again to landscape and then back to portrait has the system got back into the right state and will actually install the popover bar button item in portrait mode.
Based on this question, I also tried invoking all the rotation callbacks manually instead of firing the delegate method, e.g.:
// iOS 4 never goes inside this 'if' branch
if (UIInterfaceOrientationIsLandscape( [self interfaceOrientation] ) &&
rightRootHasButton)
{
[self willRotateToInterfaceOrientation:self.interfaceOrientation duration:0];
[self willAnimateRotationToInterfaceOrientation:self.interfaceOrientation duration:0];
[self didRotateFromInterfaceOrientation:self.interfaceOrientation];
}
However this just seems to cause an infinite loop back into viewWillLayoutSubviews :(
Does anyone know what the correct way to simulate the iOS4-style rotation events is for a split view controller that appears from behind a full-screen modal? Or should you not simulate them at all and is there another best-practices approach that has become the standard for iOS5?
Any help really appreciated as this issue is holding us up from submitting our iOS5 bugfix release to the App Store.
I don't know the right way to handle this situation. However, the following seems to be working for me in iOS 5.
In splitViewController:willHideViewController:withBarButtonItem:forPopoverController:, store a reference to the barButtonItem in something like self.barButtonItem. Move the code for showing the button into a separate method, say ShowRootPopoverButtonItem.
In splitViewController:willShowViewController:invalidatingBarButtonItem:, clear that self.barButtonItem reference out. Move the code for showing the button into a separate method, say InvalidateRootPopoverButtonItem.
In viewWillLayoutSubviews, manually show or hide the button, depending on the interface orientation
Here's my implementation of viewWillLayoutSubviews. Note that calling self.interfaceOrientation always returned portrait, hence my use of statusBarOrientation.
- (void)viewWillLayoutSubviews
{
if (UIInterfaceOrientationIsPortrait(
[UIApplication sharedApplication].statusBarOrientation))
{
[self ShowRootPopoverButtonItem:self.barButtonItem];
}
else
{
[self InvalidateRootPopoverButtonItem:self.barButtonItem];
}
}

Ipad orientation is not working well

I am creating an application with Landscape Right orientation. For that I set the Initial interface orientation property in info.plist file. Then in every view I handled
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return(interfaceOrientation==UIInterfaceOrientationLandscapeRight);
}
It works fine in simulator but in device its behave differently.
My first view is in proper orientation. There is is popover which display another view that comes in portrait mode. Still my status bar is in Landscape Right..
For navigating from one view to another view I am using..
self.window.rootViewController = self.myNav;
I have multiple navigation Controller and adding those using the upper code.
I am not getting what is the problem.
Any help will be appreciated.
EDIT: I had used
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
I never get this issue in simulator but getting this in device and not every time. I have used Supported interface orientations (iPad) too and set Landscape (right home button) value for item0.
Thanks In advance
You need to set the "Simulated Metrics > Orientation" property of your top view (in all your xib files) to be "Landscape". The default is portrait.
The question was answered pretty well here - Landscape Mode ONLY for iPhone or iPad .
I also have an app that like yours only supports UIInterfaceOrientationLandscapeRight. I haven't run into any orientation issues so far. I only have one UIViewController under the window. This UIViewController has its own UITabBar that I use to change pages. So, we change pages differently. I set my UIViewController using the rootViewController property of the window just like you, but again I only have one.
Also, I never had to do anything like the [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications] call that you included. Since you only support LandscapeRight orientation, you shouldn't care to be notified of changes.
EDIT
I created a sample project, which I can post if necessary, and I think I may know your problem. First - do you only encounter the sizing issue inside popovers? If so, then I don't think orientation is throwing you off but the popover itself. My sample project has 3 view controllers. The first loads the second by changing the window's rootViewController. That worked fine. The second view controller has a button to open a popover. This will show up wrong unless you set the contentSizeForPopover on the view controller as shown below:
- (IBAction) showVC3InPopover
{
UIViewController * vc3 = [[VC3 alloc] init];
/** Set the contentSizeForViewInPopover property to determine how
large the view will be in the popover! You can do this in the
init method(s) of the view controller if you prefer, it's just
easy to do here */
vc3.contentSizeForViewInPopover = vc3.view.frame.size;
[_popover release], _popover = nil;
_popover = [[UIPopoverController alloc] initWithContentViewController:vc3];
[vc3 release];
[_popover presentPopoverFromRect:_showPopoverButton.frame inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
See if this fixes your problem. If it does, there are other ways to control the popover size, but this is just what I typically do. However, just know that the PopoverController ignores the size of the view in the viewcontroller you load.
How many views (or viewControllers) you have? You might need to implement this orientation logic in all those views??

Resources