Issue with presenting UIImagePickerController in i

2020-07-06 07:44发布

My application runs in only landscape mode ! so I know UIImagePickerController presents only in portrait mode , so in iOS 6 , I had created a subclass of UIImagePickerController that forced UIImagePickerController to open in portrait mode:

@interface NonRotatingUIImagePickerController : UIImagePickerController

@end

@implementation NonRotatingUIImagePickerController

- (BOOL)shouldAutorotate {

    return NO;
}

@end

//presenting picker controller :

UIImagePickerController *ipc = [[NonRotatingUIImagePickerController alloc]init];
ipc.delegate = self;
[self presentViewController:ipc animated:YES completion:nil];

This worked fine in iOS 6 , but now in iOS 7 my app does crash because of this :

2013-10-31 14:56:01.028 Medad[1731:60b] *** Terminating app due to
uncaught exception 'UIApplicationInvalidInterfaceOrientation', reason:
'Supported orientations has no common orientation with the
application, and shouldAutorotate is returning YES'

This problem could be solved if I check Portrait in deployment info : enter image description here

The problem is if I check this option my app does run in portrait too but I don't want it!

How can I solve this issue?

6条回答
乱世女痞
2楼-- · 2020-07-06 08:15

Another solution.

In every controller add, even to the controller that have the picker:

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    if (interfaceOrientation == UIInterfaceOrientationLandscapeLeft
        || interfaceOrientation == UIInterfaceOrientationLandscapeRight)
    {
        return YES;
    }
    return NO;
}

- (BOOL)shouldAutorotate {
    return YES;
}

- (NSUInteger)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskLandscape;
}

Add this to your custom picker controller:

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

    return NO;
}

- (BOOL)shouldAutorotate {
    return YES;
}

- (NSUInteger)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskPortrait;
}
查看更多
一夜七次
3楼-- · 2020-07-06 08:16

Actually i had the same problem and solved it in a different way... Actually this was identified as a bug in IOS6 happens with ImageViewController which only supports Portrait orientation ... so i spent lot of time and found a way around the same....

hope this helps so first things first...

add a property in your AppDelegate.h

@property BOOL model;

then in AppDelegate.m

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // Override point for customization after application launch.
    self.model=NO;

    return YES;
}

also add this method in AppDelegate.m

- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{

    if(!self.model)
        return  UIInterfaceOrientationMaskLandscape; //or needed orientation
    else

        return UIInterfaceOrientationMaskAllButUpsideDown;


}

then in your view controller before presenting the imagepicker

implement this code...

AppDelegate *appdelegate=(AppDelegate*)[[UIApplication sharedApplication] delegate];
            appdelegate.model=YES;

and then you just change the value when you came back after picking image , ie, delegate method

AppDelegate *appdelegate=(AppDelegate*)[[UIApplication sharedApplication] delegate];
            appdelegate.model=NO;
查看更多
叼着烟拽天下
4楼-- · 2020-07-06 08:17

In every controller add:

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    if (interfaceOrientation == UIInterfaceOrientationLandscapeLeft
        || interfaceOrientation == UIInterfaceOrientationLandscapeRight)
    {
        return YES;
    }
    return NO;
}

- (BOOL)shouldAutorotate {
    return YES;
}

- (NSUInteger)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskLandscape;
}

For the controller you have the picker: Design this view with only Portrait orientation. So, it will have the same orientation of the picker. This view will be the only view with Portrait orientation while the others with landscape.

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    if (interfaceOrientation == UIInterfaceOrientationPortrait)
    {

        return YES;
    }

    return NO;
}

- (BOOL)shouldAutorotate {

    UIInterfaceOrientation orientation = [[UIDevice currentDevice] orientation];

    if (orientation==UIInterfaceOrientationPortrait) {

    }

    return YES;
}

- (NSUInteger)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskPortrait;
}

Other solutions will also crash in the views that have the picker since they don't return portrait orientation to handle the picker orientation. while not adding any code to this view controller will let this view to run in landscape and portrait.

So, my proposed solution that to run all the views in landscape and this one in portrait. having this view in portrait is more design logical to have the same orientation of the picker.

The following go into your custom picker:

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

        return NO;
    }

    - (BOOL)shouldAutorotate {
        return YES;
    }

    - (NSUInteger)supportedInterfaceOrientations {
        return UIInterfaceOrientationMaskPortrait;
    }
查看更多
别忘想泡老子
5楼-- · 2020-07-06 08:19

I have tested it and found that you should not handle the orientation via check box in target window as you shown in the above image because its your whole app orientation so please check all boxes to get all orientation supported. If you want some view in different orientations and some in different then you will have to handle it via coding in ViewController class by returning YES OR NO for orientation.

Here is my Sample. Which I made. Please check.

Below method will handle the orientation for ViewController

-(BOOL)shouldAutorotate
{
    return YES;
}

-(NSUInteger)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight;
}

// Old Method
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
    if (UIInterfaceOrientationIsPortrait(toInterfaceOrientation)) {
     return NO;
    }
    else {
        return YES;
    }
}

So, Solution is: Make two custom class one for UIImagePickerController and another is for ViewController (For All ViewControllers) and just make them for specific orientation and use those class as super class of your UIImagePickerController and all ViewControllers respectively.

查看更多
迷人小祖宗
6楼-- · 2020-07-06 08:23

There is one simple solution to avoid changing the supported orientations of your app, and make the UIImagePickerController work correctly: return UIInterfaceOrientationMaskAll only when the picker has to be presented.

You can do it simply subclassing UIApplication and using these two methods:

- (NSUInteger)supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
    UIViewController *topController = window.rootViewController;

    if ([self hasPicker:topController])
        return UIInterfaceOrientationMaskAll;

    return [super supportedInterfaceOrientationsForWindow:window];
}

-(BOOL)hasPicker:(UIViewController *)controller
{
    BOOL hasPicker = NO;

    NSLog(@"Check Controller: %@", controller);

    if ([controller isKindOfClass:[UIImagePickerController class]])
        return YES;

    for (UIViewController *child in controller.childViewControllers) {
        hasPicker = [self hasPicker:child];

        if (hasPicker)
            return YES;
    }

    return NO;
}

In the first method, you are overriding the default supportedInterfaceOrientationsForWindows: method. Every time the method is called, you check all the view controllers in the hierarchy (through hasPicker:, a recursive method). If an UIImagePickerController is found, you return UIInterfaceOrientationMaskAll, otherwise you return the default setting of your app.

Another thing I suggest you: don't subclass UIImagePickerController, since Apple explicitly forbids it. Instead, use view controller containment as I did in this example:

Landscape Picker Example

NOTE: The example code works only with UIImagePickerController containment. If you subclass it and add it through presentViewController: you may have to adjust the behavior of the hasPicker: method. One other simple thing you can do: add an instance variable to your UIApplication subclass and set it when you show the picker, and unset when you dismiss

查看更多
家丑人穷心不美
7楼-- · 2020-07-06 08:28

You should also set in the subclass:

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
    return UIInterfaceOrientationLandscapeLeft ;
}

- (NSUInteger)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskLandscape;
}

- (BOOL)shouldAutorotate {
    return YES;
}

Now you can remove from the settings "Portrait"

[EDIT] Since the UIImagePickerController can only be presented in Portrait (as per Apple doc), is possible to do the other way around, enabling portrait and landscape orientation, but fixing the orientation in landscape of everything but the picker controller. I made a little sample downloadable from here.

查看更多
登录 后发表回答