I am developing an iPhone application. My active UIViewController is vc1. The shouldAutorotateToInterfaceOrientation method of vc1 returns YES and hence the device orientation is handled for its view automatically.
All the subviews added to this view has autoresizing masks set properly to fit the orientation.
The view's frame is not updated to fit the orientation for the following scenario:
Push another UIViewController say vc2
change the device orientation
pop vc2
The new orientation is not reflected for view of vc1.
I can register for orientation change notification and manually set the frame to the view. Is there any way that handles this automatically?
I did the same. I don't think there is any way you can do this automatically.
You can probably send in a notification about the device orientation or you can check the current device orientation in ViewWillAppear and set the frame accordingly.
What exactly is your app viewController structure?
Make sure you are using a navigationController (you can have the navigationBar hidden if you like). Then it should just work.
Related
We have a MainViewController with a tableView, and it presents a new modalViewController.
The MainViewController is restricted to portrait only, and the modalViewController can rotate.
The problem is in iOS8, that when the modalViewController rotates, the callback method of rotation in iOS8 in MainViewcontroller is called - - (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
Thus, the UITableView is getting its data reloaded, which is a behaviour we don't want.
Can we prevent this feature of iOS 8, and not rotate the presenting UIViewController?
So after long days of searching and investigating, I finally came up with a possible solution.
First of all, I can use navigation controller and push the viewController instead of presenting it, but it breaks my code and just isn't so true.
The second thing I can do is not setting constraints. I still can use autolayout, but if I don't set constraints, and let the default constraints to be set, the tableView doesn't get reloaded. of course this is also isn't very smart thing to do, as I have many elements in my viewController.
Finally, I figured out that I can show this "modal" viewController in another UIWindow. I create UIWindow and set the modalViewController as its rootViewController.
I put some example project in git:
https://github.com/OrenRosen/ModalInWindow
Hope it will be helpful.
I did something similar with a navigation controller, that wouldn't rotate unless the top pushed controller does rotate.
In your case check if the main controller is presenting another controller. If it isn't then just reject rotation, otherwise return whatever the presented controller returns for the rotation method.
As for your table view, it shouldn't get reloaded because of rotations.
In iOS 8 the view that rotates when you change the device orientation is the first view added to the UIWindow. So, if you save a reference to it in your presentedController, you can overwrite the shouldAutorotate and supportedInterfaceOrientations values.
I have read multiple QAs on this topic and read the documentation, but I would like some confirmation on the answers.
- (BOOL)shouldAutorotate
This method determines if the VC is allowed to autorotate?
-(NSUInteger)supportedInterfaceOrientations
This method determines what orientations the specific View Controller accepts, is able to rotate too...
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
This method determines what the preferred orientation is for. However, it is not called on the VC but on a navigation controller. So if you wish to use you should subclass uinavigationcontroller.
Is this all correct?
What I am trying to do is have one specific controller auto rotate to landscape if an image is passed to it in that orientation. I can get the image orientation without an issue. I have set the shouldAutorotate to YES on that VC, and the supportedInterfaceOrientations is set to all. However it does not rotate.
This is from a UINavigationController that modally presents another UINavigationController on top of it and is the specific controller is about 6th in the stack.
How do I control the preferred orientation for a VC within a UINavigationController which is determined by a value from that View Controller? As the orientation would not always be the same.
Be careful you don't have orientation lock on the device whilst testing!!! Opps
I've got a universal ipad/iphone app that allows the user to watch a video, which they can then expand into full screen mode.
I have implemented (void) willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration, and in that method I perform various setFrame calls on my view elements depending on whether they are in landscape or portrait orientation.
That all seems to work fine in normal use, i.e. rotating back and forth works fine.
But if the user starts in portrait mode, starts a video, goes to full screen mode, turns into landscape orientation, and then the video stops -- the elements are often not resized properly. They appear to be sized still as if they are portrait mode.
If I then turn to portrait mode, and then turn back to landscape, the view resets correctly.
The strange part is, I have implemented (void)exitedFullscreen:(NSNotification*)notification and in there I print out the orientation, and it's seen correctly. I also call my code to reset the view elements based on the current orientation, and I am still having this problem.
Another related issue is sometimes when dealing with rotation, my views will end up too far up the screen, actually going under the status bar at the top of the device.
Edit Here's the latest example. I rotate to landscape mode during full screen video playback, and then when I left full screen video, you can see the issue with the navigation bar at the top of the view.
One possible way to solve this is by presenting your view controller modally instead of using the navigation view controller.
Refer to Kenny's answer at Problem pushViewController from Landscape to Portrait
Your ViewController might not be rotating because another controller is the first responder. What you can do to avoid this is register the view controller to the device rotation changes and implement the rotation in the selector you call when you receive such a notification.
In appDelegate:
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
In your view controller
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(didRotate:)name:UIDeviceOrientationDidChangeNotification object:nil];
In did rotate you can check the orientation with
[[UIDevice currentDevice] orientation]
The navigation bar at the top of the view. I solved it, using this code ->
[[UIApplication sharedApplication] setStatusBarHidden:NO animated:NO];
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleDefault animated:YES];
Using this after your rotation.
Mason, did you logged and checked whether your method willAnimateRotationToInterfaceOrientation:duration: gets called after each state transition?
To me this latest screenshot does not look like an orientation change issue.
The navigation bar is basically off by the status bar's height.
Possibly your position calculation fails because you are using the view's frame
while the fullscreen video (w/o status bar) is playing and this fails as soon as
the statusbar is back?
Your orientation may not get updated properly if there is another controller acting as a first responder. The best way to overcome this is to call the functions you use to orientate the screen at the method viewWillAppear: using the current orientation of the view controller: [self interfaceOrientation]
If you use a subclassed subview you may need to reimplement the methot layoutSubviews and call setNeedsLayout. Another thing that may be causing this is resigning the viewcontroller where you have the video as first responder (you mays search if somewhere you use the methon resignfirstresponder and try how it works without it). If this does not work, I don't know, this things may be very tricky and dependent on how you have implemented it. But for the things you say you do you should not need much code, since automatic rotation and resizing of views is handled now by the sizes inspector of the views editor.
I think that this should do.
I'm developing an iPad app that launches in landscape mode.
The first screen displays a UISplitViewController and my issue is that altough the app is in landscape mode the delegate is notified on splitViewController:willHideViewController:withBarButtonItem:forPopoverController: despite that the documentation states that:
When the split view controller rotates
from a landscape to portrait
orientation, it normally hides one of
its view controllers. When that
happens, it calls this method to
coordinate the addition of a button to
the toolbar (or navigation bar) of the
remaining custom view controller. If
you want the soon-to-be hidden view
controller to be displayed in a
popover, you must implement this
method and use it to add the specified
button to your interface.
As the app is in landscape mode and not transitioning to portrait I don't get why my delegate is notified. Why is it so?
valentin, to directly answer "why is it so?", i think the answer is simply that it's a bug in the implementation of their API.
as you seem to have found, when in landscape orientation, it calls the above when it sort of seems that it shouldn't, and then calls splitViewController:willShowViewController:invalidatingBarButtonItem: .
also, i discovered that when in portrait orientation, it sends a very early message (i.e. before the view.frame has been adjusted) to splitViewController:willHideViewController:withBarButtonItem:forPopoverController: .
the one thing i saw that annoyed me the most was that, using the code provided from their template creation, the button bar would appear and then disappear at startup.
my solution was to implement a workaround, which i have posted on git#github.com:johnkdoe/freeforall.git in the class KludgeWorkaroundForBuggySplitViewDelegateStartup .
make this a superclass of your current detail view controller class, as in
//#interface MyViewController : UIViewController<UISplitViewControllerDelegate>
#interface MyViewController : KludgeWorkaroundForBuggySplitViewDelegateStartup
this will set the initial button bar title to Master if you don't have something you prefer. you can override this by overriding the #property getter in your subclass implementation. if you want to do more than what's in this kludgeWorkaround class, you can override these yourself and (either copy and paste or) call [super ...] on them prior to doing your own work.
i can't say this solves the problem of what appears to me to be an implementation bug, but the workaround gets rid of the brief appearance of the button bar at startup of a split-view-controller app in landscape mode.
How does a UISplitViewController know when it has rotated so that it can trigger the appropriate behavior with managing its views? Is there some way I can manually trigger it myself? I have a split view controller owning a view that is not at the root of my hierarchy, so it is not getting the rotation events that (I think) normally allow it to handle rotation behavior.
You can try to implement UISplitViewController delegate which is:
// Landscape mode
– splitViewController:willShowViewController:invalidatingBarButtonItem:
// Portrait mode
– splitViewController:willShowViewController:invalidatingBarButtonItem:
Since the masterView (left) will show/hide accordingly when the rotation occurs, I found this is more effective compared to handling the orientation changes if each view
I guess UiSplitViewController doesn't autorotate and
iPad: SplitView does not rotate pretty much say that unless the controller's view is the root view, it won't work. Oh apple.
You could sign up for notifications of orientation changing, make sure you have shouldAutorotateToInterfaceOrientation set to YES for the rotations you want to support as well.