I haven’t seen a definitive answer to this question yet, lots of noise around the iOS 8 changes, but I’d like to address it for iOS 9:
What is the correct way to get a callback after an interface orientation change ENDS?
As of iOS 9, didRotateFromInterfaceOrientation: has been deprecated, and the official documentation tells us to use viewWillTransitionToSize:withTransitionCoordinator instead. This gives us (through the transitionCoordinator) a means of animating alongside the transition, and a completion block, but no direct callback for the bona fide ‘end’ of the transition.
The other method from the transitionCoordinator is notifyWhenInteractionEndsUsingBlock:, but this appears to report the end of the interactive part of the transition, not the entire thing.
So, is the “official” way to do this to implement animateAlongsideTransition:completion, and simply ignore the animation option?
I realise we can still use good old didRotateFromInterfaceOrientation:, but it’s always better to modernise where possible.
Yes, you can ignore animation option, just use 'nil' for it.
Example from WWDC 2014 'View Controller Advancements in iOS 8':
- (void) viewWillTransitionToSize:(CGSize)s withTransitionCoordinator:(UIVCTC)t
{
orientation = [self orientationFromTransform: [t targetTransform]];
oldOrientation = [[UIApplication sharedApplication] statusBarOrientation];
[self myWillRotateToInterfaceOrientation:orientation duration:duration];
[t animateAlongsideTransition:^(id <UIVCTCContext>) {
[self myWillAnimateRotationToInterfaceOrientation:orientation duration:duration];
}
completion: ^(id <UIVCTCContext>) {
[self myDidAnimateFromInterfaceOrientation:oldOrientation];
}];
}
Works fine with iOS 9.
Related
The Problem - Preparing and showing an MFMessageComposeViewController is trivial as per the Apple docs. What I need to know is when this has been fully presented.
Explanation - Showing the MFMessageViewComposeController with a completion block is easy, but doesn't solve my problem:
[self presentViewController:messageController animated:YES completion:^(void){
//Controller has been shown. But not really....
}];
The problem is more obvious for messages to larger groups of recipients (say 50 people). The completion block gets called, but the phone's screen remains black. Several seconds later, the messaging window appears. Several seconds later, the recipient list becomes active with a flashing cursor. Basically, there's a lot of loading and processing that goes on after the controller has supposedly been presented.
What I'd like - To figure out when the interface has been fully loaded. I don't expect a simple answer, and I've already spent quite a bit of time on it - definitely bounty worthy. If you can post a working answer with code I'll award maximum bounty for it.
Just check MFMailComposeViewController view's frame. Once it achieves top of the screen handle the appearance.
[self presentViewController:messageController animated:YES completion:^
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^
{
while(messageController.view.frame.origin.y > 0)
{
}
dispatch_async(dispatch_get_main_queue(), ^
{
// Handle appearance of MFMailComposeViewController
});
});
}];
The other way is to wait 0.3 seconds using dispatch_after() method. But this time interval could be changed next versions of iOS.
I am implementing according to kamcord tutorial :
https://github.com/kamcord/kamcord-ios-sdk/wiki/Getting-Started#wiki-kamcord-initialization
My app is a simple ios app not using the cocos2d game engine.
and for some reason I cannot see it working.
Here is the code implemented in app delegate :
_view_controller = [[ViewController alloc]init];
// Override point for customization after application launch.
// that will present the Kamcord UI.
[Kamcord setDeveloperKey:#"key"
developerSecret:#"secret"
appName:#"appName"
parentViewController:_view_controller];
and I call this methods from the viewController:
- (IBAction)stopRecording:(id)sender {
[Kamcord stopRecording];
NSLog(#"Stop");
}
- (IBAction)startRecording:(id)sender {
[Kamcord startRecording];
NSLog(#"Start");
}
-(IBAction)showUpKamcord{
[Kamcord showViewInViewController:self];
NSLog(#"kamcord");
}
First I start recording, then stop and after that I am showing the view,
any ideas?
Kamcord only works with OpenGL views. It does not record UIKit, so that won't work if that's what you're looking for.
I know this is an older question, but for those that stumble upon it looking for a solution to record your non-Open GL based screens, there is a project called ASScreenRecorder https://github.com/alskipp/ASScreenRecorder that allows you to record your UIKit based app screens and it's extremely simple to get working.
I have a UIViewcontroller that hosts a lot of Viewcontrollers. I set up autorotating on it and its subview and it works fine once the app has loaded. The problem I have is that during the initial loading process, the app has to connect and download some files locally. During this load if the user rotates the iPad the UIViewController doesn't rotate properly! I did set the flags and shouldautorotate but still not working.
PS : I am allowing these four orientations :
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait ||
interfaceOrientation == UIInterfaceOrientationLandscapeLeft ||
interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown ||
interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}
After the load is complete the behavior is correct and rotates properly. Now I thought this could be because some of those inner VC's are loading some data, let me explain:
The big View Controller hosts all other VC's ( Let's Call him BigDaddy), in the Viewdidload of bigdaddy I have (for argument sake ) three other ViewControllers : Busta, Skeezix, and lawrence. So I do:
[[Busta alloc] initWithNibName:#"Busta" bundle:nil];
and this in turn calls the -viewDidLoad of Busta, so I made the file loading section of that asynchronous by doing:
dispatch_async(dispatch_get_main_queue(), ^{
});
Those changes did help a little bit, in the sense that before the async dispatch the load process would take 5 seconds (and in those seconds any tilt in the iPad would cause the rotation event and my whole view is gone. Now I got those 5 seconds down to 1.2 seconds.
My question is, is there a solution to my problem? Will it never work? Is it possible to have an app rotate in four directions and respond to rotation changes while loading data?
I suspect the issue is with how you're doing your 'connect'. I assume you mean you're connecting to a remote server using NSURLConnection or similar. Be aware that if you use a synchronous connection on the main thread, you will freeze the app until the connection is finished. The appropriate method is to utilize the asynchronous calls, or better yet move the work to a secondary thread (see NSOperationQueue documentation) and then move any updating of the UI based on that information back to the main thread (see again the NSOperationQueue documentation).
There is a good example for this in the WWDC 2012 videos.
Why not just implement your -shouldAutorotateToInterfaceOrientation... method such that it allows rotation only after the app has finished loading the required data?
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
BOOL appIsFinishedLoadingData = <your code here>
return shouldRotate;
}
(I shortened your code in consideration of the fact that you're allowing all possible rotations, so there's really no need to check which rotation is being offered. Your way is more future-proof, mine is a little easier to read.)
I have static library and my custom view controller inside (f.e mainVC).
My static library will be built in some third party application.
I have to show mainVC.view instantly after third app did launch.
I do:
[window addSubView:mainVC.view];
but how can I do my mainVC active? It means I have to deny landscape orientation in
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
and this method never calls in this case.
I've also tried to call manually
[self.mainVC viewWillAppear:NO];
but still unsuccessful.
Maybe I should use
-(void)presentModalViewController:animated
but it's deprecated. And I have to support IOS 4.3
You might want to check if the class is allowed to respond to the method before you call it.
if([self respondsToSelector:#selector(presentViewController:animated:completion:)])
{
[self presentViewController:viewController animated:YES];
}
else
{
//some other methods
}
This way you can use the deprecated method for support with IOS 4.3, and use another solution for later IOS versions
I am working in flash CS5.5 on an app for iOS. I want to get the ipad/iphone to stop animating the orientationChange and just change it directly, is this possible?
I thought this was a solution but it didnt help AS3 - iOS force landscape mode only?.
If you try setting Stage.autoOrients = false;, the flash.events.StageOrientationEvent.ORIENTATION_CHANGE will never fire. That's helpful for disabling orientation changes altogether, but not for your issue. While I haven't tried it myself, you may be able to listen to the event:
flash.events.StageOrientationEvent.ORIENTATION_CHANGING
You may be able to call event.preventDefault() in that listener to stop the actual rotation from occuring. Then you can manually set it yourself:
Stage.setOrientation(StageOrientation.ROTATED_RIGHT);
have you tried the SO answer: Disable orienation change rotation animation ?
the code from that answer that goes in the view-controller that is the home for your flash CS5.5 or air 3.5 is:
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
[UIView setAnimationsEnabled:YES];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
[UIView setAnimationsEnabled:NO];
return TRUE; /* Your original orientation booleans, in case you prevent one of the orientations */
}
that code makes use of native iOS UIViewController functions that can be overridden. you would have to have a native iOS objective C class that overrides UIViewController, and then you could insert the code above. calls are made when the device is rotated to these as part of view controller life cycle.