iPhone, duplicate method message after hardware rotate? - iphone

I am pretty sure what I am seeing is how this is supposed to work, but I as just curious as to why. When I rotate the iPhone in the simulator the method (see below) that allows the orientation gets called twice with each single rotation. Is there a reason for this?
-(BOOL)shouldAutorotateToInterfaceOrientation:interfaceOrientation
EDIT_001
This is what gets called when the iPhone detects a rotation, I am just curious that each time I do a rotate in the simulator the NSLog statements print twice (i.e. the method is getting called twice)
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
BOOL autoRotate = NO;
switch(interfaceOrientation) {
case UIInterfaceOrientationPortrait:
NSLog(#"Orientation(%d): Portrait Supported", interfaceOrientation);
autoRotate = YES;
break;
case UIInterfaceOrientationPortraitUpsideDown:
NSLog(#"Orientation(%d): UpsideDown unsupported", interfaceOrientation);
autoRotate = NO;
break;
case UIInterfaceOrientationLandscapeLeft:
NSLog(#"Device: RIGHT, Interface: LEFT(%d)", interfaceOrientation);
autoRotate = YES;
break;
case UIInterfaceOrientationLandscapeRight:
NSLog(#"Device: LEFT, Interface: RIGHT(%d)", interfaceOrientation);
autoRotate = YES;
break;
}
return(autoRotate);
}
gary

Have you checked the arguments passed in to shouldAutorotateToInterfaceOrientation:? I have found it gets called one for horizontal, and once for vertical - basically to ask which orientations are OK, and then it's usually not called again.
If you are doing something in there you want done every time the device is rotated, I think it's a lot better to either use willRotateToInterfaceOrientation:duration: or listen for the rotation notifications (via UIDeviceOrientationDidChangeNotification), and leave shouldAutorotateToInterfaceOrientation: to flag what your app allows for rotation of that view controller.

This happens when the view is inside a tab controller, because the tab controller also calls that same method. Hope that helps.
-Oscar

Related

How to allow only particular view to rotate? (iPhone)

I am installing AdMob's ad, and there is a GADBannerView.
After installing, a banner show, and if you click on it, a page will slide out coving the whole screen, and displaying advertising contents in it.
The question is, some advertising contents, such as video, had to be played landscape. However, I don't want other part of my application to rotate, as the app is not designed to be viewed in landscape.
So, how can I implement something which can achieve such function?
Try to use Notification for this. a notification calls a selector every time when ur device orientation is changed.
write this in your viewDidLoad:
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(setScreenWithDeviceOrientation:) name:#"UIDeviceOrientationDidChangeNotification" object:nil];
and then define the selector as follows:
-(void)setScreenWithDeviceOrientation:(NSNotification *)notification
{
UIDeviceOrientation orientation=[[UIDevice currentDevice] orientation];
if(orientation==UIInterfaceOrientationPortrait) //Portrait orientation
{
// setView frame for portrait mode
}
else if(orientation==UIInterfaceOrientationPortraitUpsideDown) // PortraitUpsideDown
{
// setView frame for upside down portrait mode
}
else if(orientation==UIInterfaceOrientationLandscapeLeft)
{
// setView frame for Landscape Left mode
}
else if(orientation==UIInterfaceOrientationLandscapeRight) //landscape Right
{
// setView frame for Landscape Right mode
}
else
{
NSLog(#"No Orientation");
}
}
this method fired everytime when ur device changes orientation. Based on the current orientation you should adjust your view.
I hope this will help you.
Are you working with iOS 6? You should be able to just restrict what orientations your view controller handles in this case. For example, in your view controller that handles your GADBannerView, you can just put:
// Tell the system what we support
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskPortrait;
}
// Tell the system It should autorotate
- (BOOL) shouldAutorotate {
return NO;
}
// Tell the system which initial orientation we want to have
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return UIInterfaceOrientationPortrait;
}
And that should make it so that your viewcontroller only supports portrait.
Have you looked at this question and answer? This explains how a single view can work in a certain orientation that is not supported by the rest of the application:
AutoRotate ONLY MpMoviePlayerControler iOS 6

issue about willAnimateRotate and didRotateFrom when doing an rotation

What I am having so far is
-(void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
NSLog(#"willAnimateRotationToInterfaceOrientation");
if(toInterfaceOrientation == UIInterfaceOrientationPortraitUpsideDown) {
NSLog(#"PortraitUpsideDown");
// Do method A
} else {
[[self.view subviews] makeObjectsPerformSelector:#selector(removeFromSuperview)];
// Do method B
}
}
and
-(void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
NSLog(#"didRotateFromInterfaceOrientation");
if( fromInterfaceOrientation == UIInterfaceOrientationPortrait || fromInterfaceOrientation == UIInterfaceOrientationPortraitUpsideDown){
NSLog(#"OrientationPortrait or PortraitUpsideDown");
[[self.view subviews] makeObjectsPerformSelector:#selector(removeFromSuperview)];
// Do method B
} else {
NSLog(#"From else");
[[self.view subviews] makeObjectsPerformSelector:#selector(removeFromSuperview)];
// Do method A
}
}
My logic is after hitting the RUN from xcode, willAnimateRotationToInterfaceOrientation: is going to be called because I set Supported Device Orientation to be UpsideDown from Summary of MyApp.xcodeproj. Moreover, I also think that didRotateFromInterfaceOrientation: should not be called because we have just started the app yet. It means there are no previous states at all.
Unfortunately, this is what I got after doing the debugger
2012-02-11 12:04:08.776 MyApp[7505:10703] willAnimateRotationToInterfaceOrientation :
2012-02-11 12:04:08.776 MyApp[7505:10703] PortraitUpsideDown
2012-02-11 12:04:08.778 MyApp[7505:10703] didRotateFromInterfaceOrientation :
2012-02-11 12:04:08.779 MyApp[7505:10703] OrientationPortrait or
PortraitUpsideDown
I am getting lost now. Does anyone have any ideas about the issue, please help. Thanks.
I have had some issues with rotation, similar to yours. The short version is that the will and did methods are not 100% reliable. You should try rapidly rotating back and forth and see what happens. It could be because I am pretty new, or it could be an actual bug. What I did was, in didRotateFromInterfaceOrientation:, check the current orientation and act accordingly:
if (UIInterfaceOrientationIsPortrait(self.interfaceOrientation) {
// do your portrait stuff
} else {
// do your landscape stuff
}
Before I found the UIInterfaceOrientationIsPortait test I was actually checking the frame to see if self.view.frame.size.width > self.view.frame.size.height, and that is also reliable but kind of ugly.
Either way is reliable. I have a couple apps in the store, QPalettes and QColor, that do rotation on a bunch of user-created onscreen elements. What I had to do is store the dimensions, and after didRotateFromInterfaceOrientation I check the new dimensions and if they are different, re-draw everything onscreen. Contact me if you'd like a promo code to check out the rotation in either app (they rotate the same - QColor is more complex since it also draws intersections).
Enjoy,
Damien

Handle orientation when showing a view

I have a few changes that get made to a UIView when the orientation changes. This works fine. The problem arises when adding the view after the phones orientation is already switched. This causes none of the rotate methods to be called and therefor does not give me the opportunity to make changes.
What would be the correct way of handling this, probably in ViewDidLoad? Would I be able to detect the current orientation at that point?
Bare in mind that its a few minor changes that I would need to make, so I dont want to load a different nib or anything like that
Thanks you very much :)
EDIT* just to clear things up: As I mentioned, the view is not even instantiated yet when the device orientation changes. The orientation changes to landscape -> the user clicks a button that shows another view -> this new view gets created and shown, but its default positioning is for portrait orientation -> when the view is shown, the elements I rearrange in the willAnimateRotationToInterfaceOrientation method are in the wrong position.
Typically I put the animations that occur when the user rotates the device (manipulating the frames of views mostly) in the willAnimateToInterfaceOrientation method. In it's skeleton form it would look like this:
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
duration:(NSTimeInterval)duration
{
//NSLog(#"willAnimateRotationToInterfaceOrientation: %d", toInterfaceOrientation);
if (UIInterfaceOrientationIsPortrait(toInterfaceOrientation))
{
// portrait
}
else
{
// landscape
}
}
EDIT: In situations where I need to remember the device rotation for future use, I set up an ivar in my view controller class called currentOrientation (type int), and then do this:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
//NSLog(#"shouldAutorotateToInterfaceOrientation: %d", toInterfaceOrientation);
if (toInterfaceOrientation == UIDeviceOrientationPortrait || toInterfaceOrientation == UIDeviceOrientationPortraitUpsideDown ||
toInterfaceOrientation == UIDeviceOrientationLandscapeLeft || toInterfaceOrientation == UIDeviceOrientationLandscapeRight)
{
currentOrientation = toInterfaceOrientation;
}
return YES;
}
Then while running the methods in the view controller, I know which orientation the device is in.

UIViewController does not auto rotate

As the title says. My UIViewController will not rotate no matter what. When it loads shouldAutorotateToInterfaceOrientation is being called but after that it doesnt.
UPDATE 1:
It's a really really wierd problem. At least for me. And i ll try to explain everything.
It's a navigation based app. Every controller has
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation{
return YES;
}
Xcontroller is a child of Acontroller and it doesn't auto rotate. If Xcontroller become a child of Bcontroller then it will autorotate. So something is wrong with Acontroller. But Acontroller is identical (except its data) to Bcontroller.
Whats Wrong?
UPDATE 2:
I decided to recreate Acontroller. And it worked.I believe I was missing something stupid.
I am not sure whether it's the same reason as your case. But I experienced the same thing. the shouldAutorotateToInterfaceOrientation was only called once in the beginning.
After some serious debugging by taking code apart, I found that the reason is in my overridden init method.
I had this before:
- (id)initWithAlbum:(PhotoAlbum *)theAlbum {
if (self) {
self.photoAlbum = theAlbum;
}
return self;
}
And then I changed to this
- (id)initWithAlbum:(PhotoAlbum *)theAlbum {
if (self = [super init]) {
self.photoAlbum = theAlbum;
}
return self;
}
Note: the only difference is I added [super init] to call the parent init.
After this change, the rotation works well and the shouldAutorotateToInterfaceOrientation is being called everytime I rotate the screen.
Hope this help.
There can be several possible reasons your view controller does not rotate.
See Apple's official Q&A on this issue:
Why won't my UIViewController rotate with the device?
http://developer.apple.com/library/ios/#qa/qa2010/qa1688.html
Apple Q&A has the detailed solution for the problem.
Why won't my UIViewController rotate with the device?
http://developer.apple.com/library/ios/#qa/qa1688/_index.html
If you add a viewcontroller.view to uiwindow, you should set this viewcontroller as rootviewcontroller.
[self.window addSubview: mainViewcontroller.view];
self.window.rootViewController=mainViewcontroller;
Also, make sure you don't have rotation lock on. I spent a good hour trying to figure out why my views stopped rotating. shouldAutorotateToInterfaceOrientation was being called only once at start up and when Game Center leaderboards/achievements were presented.
I had the same issue - the reason was, that it was my first UIViewController, that i created on the fly in my ApplicationDelegate, added it's View to my UIWindow and immediately released it.
That's of course not correct as I just added the UIView of the UIViewController (retaining it) and than released the whole controller.
You should add your first UIViewController as an instance variable in Your ApplicationDelegate instead, and release it in Your ApplicationDelegate's dealloc-method.
In my case, the ViewController was inside a NavigationController which was used by a "parent" viewControlled that received the orientation changes.
What I did in this parent was:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation{
if(_navigationController){
return [_navigationController.topViewController shouldAutorotateToInterfaceOrientation: toInterfaceOrientation];
}
return toInterfaceOrientation == UIInterfaceOrientationPortrait;
}
This way you can implement your own orientation change logic depending on the currently visible controller.
(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation{ return YES; }
The above method if u using, you will able to call many time if u want with out any error.
I think there is no strange behavior here, it is called only one which is right. There is no need to call more than one to decide if the device should rotate to a direction or not.
This method just ask if the device should rotate to a direction or not.
If you want to handle the orientation change, you should register for the notification from the UIDeviceDidChangeOrientationNotification and override the following method:
- (void)orientationChanged:(NSNotification *)notification
{
UIDeviceOrientation deviceOrientation = [UIDevice currentDevice].orientation;
if (UIDeviceOrientationIsLandscape(deviceOrientation) &&
!isShowingLandscapeView)
{
[self presentModalViewController:self.landscapeViewController
animated:YES];
isShowingLandscapeView = YES;
}
else if (deviceOrientation == UIDeviceOrientationPortrait &&
isShowingLandscapeView)
{
[self dismissModalViewControllerAnimated:YES];
isShowingLandscapeView = NO;
}
}
See more here.
I have the same problem but with two view controllers added to the application's UIWindow. The reason
is The view controller's UIView property is embedded inside UIWindow but alongside an additional view controller
From Apple Technical Q&A
http://developer.apple.com/library/ios/#qa/qa1688/_index.html

Changing modal UIView's orientation to landscape mode on iPhone

Im having a modal view displayed on top of tab bar controller the orientation of tab bar controller and my modal view is currently in portrait mode, i need to only change my modal views orientation to landscape mode,
i Tried usign UIDevice Orientation but no success it only works when .plist has UIDeviceOrientationKey, and i dont want whole of my application in landscape mode. secondly i even tried using UIApplication setStatusBarOrientation but my view doesn't respond to it i.e. only my device(simulator) get rotated but the view still remains in portrait mode, using affine transformation on UIView creates an empty view my view is created through XIB.
Please Help
Thanks Rakesh
I have used this and it works well with some tweaking.
Until today I used the following solution:
-(void)setOrientation:(UIInterfaceOrientation)orientation
{
SEL rotation = #selector(_setRotatableViewOrientation:duration:);
NSMethodSignature * methodSignature = [window methodSignatureForSelector:rotation];
if (methodSignature)
{
NSInvocation * ivc = [NSInvocation invocationWithMethodSignature:methodSignature];
[ivc setTarget:window];
[ivc setSelector:rotation];
// arg0 will be self, 1 will be cmd_ (current method selector)
[ivc setArgument:&orientation atIndex:2];
double duration = 0.4;
[ivc setArgument:&duration atIndex:3];
[ivc invoke];
}
}
-(void)normalizeOrientation
{
UIDeviceOrientation dOrientation = [UIDevice currentDevice].orientation;
int orientation = -1;
switch(dOrientation)
{
case UIDeviceOrientationPortrait:
orientation = UIInterfaceOrientationPortrait;
break;
case UIDeviceOrientationPortraitUpsideDown:
orientation = UIInterfaceOrientationPortraitUpsideDown;
break;
case UIDeviceOrientationLandscapeRight:
orientation = UIInterfaceOrientationLandscapeLeft;
break;
case UIDeviceOrientationLandscapeLeft:
orientation = UIInterfaceOrientationLandscapeRight;
break;
}
if (orientation != -1 && orientation != tabBarController.interfaceOrientation)
[self setOrientation:orientation];
}
but the official AppStore wont accept new releases of my App due to
_setRotatableViewOrientation:duration:transition:toView:
isn't documented API.
So be aware for use it in your commercial projects!
Apple new automated API checker will reject your App!