auto-rotation in iOS5/6?

2019-06-25 12:18发布

问题:

I updated to Xcode 4.5 and am working with iOS6--a mistake I will definitely not make next time there's an update; it's been sort of nightmarish for somebody so new to iOS--and I've just noticed an app I'm working on is autorotating. I never noticed it autorotatin before the update, but it's also possible I just didn't rotate the phone while testing, so I can't be sure. I've added the following code to the main UIViewController and it's still rotating:

- (BOOL)shouldAutorotateToInterfaceOrientation:
(UIInterfaceOrientation)interfaceOrientation
{
    return NO;
}

Is this the right way to disable autorotation? If it is, then maybe there's some change in iOS6 and I'll have to wait until the full release to find out. But if I've gotten it wrong, what code should I use instead?

Thanks, as always, for your help.

EDIT: Here's the code I changed it to, but it's still rotating. Have I gotten it wrong?

- (BOOL)shouldAutorotateToInterfaceOrientation:
(UIInterfaceOrientation)interfaceOrientation
{
if (interfaceOrientation == UIInterfaceOrientationPortrait)
{
    return YES;
}
else 
{
    return NO;
}
}

回答1:

that is because there was never a success. You should choose one of the orientations.

Hold command and click on UIInterfaceOrientation you will see an enumeration of the possible options.

then you can test against those to decide your YES Scenario.

I may have originally misunderstood your problem. It seems that you may have been saying that your app is allowing rotation. but the code should disallow that.

I was thinking you were saying it was still firing the code. Trying to find a Yes

One thing to think about. is there may be more than one view controller available. perhaps your code is not being hit.

A couple of possible issues for this.

  1. Your code is not even being used. because the view is being allocated as UIViewController as opposed to your custom view controller.

  2. You code is being used but that View controller is not the one being asked about the Orientation. therefore that specific code is not being hit.

  3. A bad build keeps putting the wrong assemblies onto the device.

Your solutions can be as follows.

  1. Ensure your code is the one being allocated. Either there is a direct alloc on your custom class. or the xib file is inflating it. Check out the Identity Inspector when you have your xib file open. select your View Controller and ensure that custom class is set to your class type

  2. Look at the hierarchy. what other view controllers are there. Perhaps one of those are telling the app it can autorotate to any orientation.

  3. Find your "DerivedData" folder and remove it entirely. Sometimes this works from the organizer. other times you need to delete directly off the disk. Then clean and build again.

Also another solution could be as simple as setting the settings in the Project file.

Select your project file from the file browser and you will see the iPad and iPod settings in the summary. You can "UnPress" buttons for the orientations that you want to disallow. and any view controllers that you do not otherwise code orientation into. will use these by default.

My apologies for the confusion.

Update

I commonly use this code to handle my autorotation.

It not only differentiates the ipad from the other ios devices, but it also forwards the request onto presented controllers so a view that is shown modal may respond how it wants.

Orientation is a pain when you dont understand it :)

// Detect iPad
#define IS_IPAD() ([[UIDevice currentDevice] respondsToSelector:@selector(userInterfaceIdiom)] ? \
[[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad : NO)

// Set preferred orientation for initial display
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{
    if (IS_IPAD()){
        return UIInterfaceOrientationLandscapeRight;
    }
    else {
        return UIInterfaceOrientationPortrait;
    }
}
// Return list of supported orientations.
- (NSUInteger)supportedInterfaceOrientations{
    if (self.presentedViewController != nil){
        return [self.presentedViewController supportedInterfaceOrientations];
    }
    else {
        if (IS_IPAD()){
            return UIInterfaceOrientationMaskLandscapeRight;
        }
        else {
            return UIInterfaceOrientationMaskAll;
        }
    }
}

// Determine iOS 6 Autorotation.
- (BOOL)shouldAutorotate{
    UIDeviceOrientation orientation = [UIDevice currentDevice].orientation;
    // Return yes to allow the device to load initially.
    if (orientation == UIDeviceOrientationUnknown) return YES;
    // Pass iOS 6 Request for orientation on to iOS 5 code. (backwards compatible)
    BOOL result = [self shouldAutorotateToInterfaceOrientation:orientation];
    return result;
}
// handle iOS 5 Orientation as normal
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation{
    // Return YES for supported orientations

    if (self.presentedViewController != nil){
        return [self.presentedViewController shouldAutorotate];
    }
    else {
        if (IS_IPAD()){
            return (interfaceOrientation == UIInterfaceOrientationLandscapeRight);
        }
        else {
            return (interfaceOrientation == UIInterfaceOrientationPortrait);
        }
    }
}


回答2:

Rotation APIs have changed in iOS6. The new API's are apparently supposed to be opt in however they seem to be enabled for all debug builds on simulator or device. To register for the new API calls throw something like this in your APP Delegates didFinishLoading method.

//Register for new API rotation calls
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"UIApplicationSupportedInterfaceOrientationsIsEnabled"];

At the heart of the rotation changes are two methods (theres a third but Im still figuring this out myself)

- (BOOL)shouldAutorotate
- (NSUInteger)supportedInterfaceOrientations

You need to override these methods in your windows rootViewController. This means you need to subclass UINavigationController or UITabBarController if either is your root controller (this seems bizarre to me, but Apple says Jump).

Now if all you want to do is keep your app in portrait implement the two methods and you're golden.

- (BOOL)shouldAutorotate
{
    return NO;
}

- (NSUInteger)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskPortrait;
}

Note that apple has further added to the confusion by adding interface orientation masks, ie. UIInterfaceOrientationMaskPortrait != UIInterfaceOrientationPortrait. If you return UIInterfaceOrientationPortrait instead the behaviour will be different. Also you can combine masks the same way you combine orientations so if you wanted to support both portrait orientations you could use.

- (BOOL)shouldAutorotate
{
    return YES;
}

- (NSUInteger)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown;
} 

That should work for forcing a portrait orientation. Now if you if you want do do something like allow a child controller to use a different orientation I have no clue.



回答3:

A very simple way to handle autorotation in both iOS6 and iOS5 is to use supportedInterfaceOrientations & shouldAutorotateToInterfaceOrientation. There are some macros to make it just a line of code. UIInterfaceOrientationIsLandscape & UIInterfaceOrientationMaskLandscape. I discovered UIInterfaceOrientationMaskLandscape & UIInterfaceOrientationMaskPortrait by auto-completion in xCode. It is not in the Apple docs about autorotation.

Add this code block to your root ViewController to force it to support only landscape mode.

//iOS6 code to support orientations
- (NSUInteger)supportedInterfaceOrientations
{
     return (UIInterfaceOrientationMaskLandscape);
}

//iOS5 code to support orientations
 - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orientation
{
     return (UIInterfaceOrientationIsLandscape(orientation));
}

For iOS6 you can use the following to detect orientation:

  • UIInterfaceOrientationMaskLandscape
  • UIInterfaceOrientationMaskPortrait
  • UIInterfaceOrientationMaskLandscapeRight
  • UIInterfaceOrientationMaskLandscapeLeft
  • UIInterfaceOrientationMaskPortraitUpsideDown
  • UIInterfaceOrientationMaskAllButUpsideDown
  • UIInterfaceOrientationMaskAll

For iOS5 and below you can use the following to detect orientation:

  • UIInterfaceOrientationIsLandscape (A macro)
  • UIInterfaceOrientationIsPortrait
  • UIInterfaceOrientationIsLandscapeRight
  • UIInterfaceOrientationIsLandscapeLeft
  • UIInterfaceOrientationIsPortraitUpsideDown