Search code examples
iosuipopovercontroller

UIPopover : handle different orientations


I am working on an application and have tons of popovers.showing up from buttons from subviews , navigation bar items etc. But they must always appear in the center of the screen. So I hard coded the presenting rect and got them to appear in the center. This was all in portrait mode. Now i have to make the application work in Landscape as well. Sicne the coordinates are handcoded. It is just not working. How can I solve this problem ? Thanks


Solution

  • I ended up writing following class. Basically all popover were 560,545 size so i hardcoded that.

    AnimatedViewController.h

    #import <UIKit/UIKit.h>
    
    /*
     Animated popover class.
    
     This class intherits from the UIPopover controller class to add following 
     functionality
    
     * Add a full screen translucent black bacground
     * Popover appears to be sliding up from bottom of the screen
     * Presents the viewController used to initialize the popover controller
       in the center of the screen
     * Always presents the Popover from the topViewController.view and never from a 
       subview
     * Register to orientation change notification.
    
     Also see @KSCustomPopoverBackgroundView for formatting of the view controller.
    
     */
    
    @interface AnimatedPopoverController : UIPopoverController{
        UIView* blackTranslucentBackGround;
        UIView* animatingView;
        UIView* mainView;
    }
    
    
    - (id)initWithViewControllerContent:(UIViewController*)viewController;
    
    -(void)presentPopover;
    
    @end
    

    AnimatedViewController.m

    #import "AnimatedPopoverController.h"
    #import "Utilities.h"
    
    @implementation AnimatedPopoverController
    
    - (id)initWithViewControllerContent:(UIViewController*)viewController{
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didRotate:) name:UIDeviceOrientationDidChangeNotification object:nil];
        self = [super initWithContentViewController:viewController];
        if (self){
            CGSize fullScreenSize = [[UIScreen mainScreen] bounds].size;
            [viewController.view setBackgroundColor:[UIColor clearColor]];
            mainView = viewController.view;
    
            // Create the center view
            animatingView = [[UIView alloc] initWithFrame:CGRectMake(0,
                                                                     0,
                                                                     560,
                                                                     545)];
            for (UIView* subview in [viewController.view subviews]){
                [animatingView addSubview:subview];
            }
            [viewController.view addSubview:animatingView];
            // Create black backdrop
            blackTranslucentBackGround = [[UIView alloc]
                                          initWithFrame:CGRectMake(0,0,fullScreenSize.width,fullScreenSize.height)];
    
            [blackTranslucentBackGround setAlpha:0.5];
            [blackTranslucentBackGround setBackgroundColor:[UIColor blackColor]];
            [viewController.view addSubview:blackTranslucentBackGround];
            [viewController.view sendSubviewToBack:blackTranslucentBackGround];
            [self setPopoverLayoutMargins:UIEdgeInsetsMake(0,0,0,0)];
            [self setPopoverBackgroundViewClass:[KSCustomPopoverBackgroundView class]];
    
        }
        return self;
    }
    
    - (void) presentPopover{
        [self centerViewForOrienation];
        [self slideAnimation:animatingView];
        UIViewController* topViewController = [Utilities topMostController];
        [self presentPopoverFromRect:topViewController.view.frame
                              inView:topViewController.view
            permittedArrowDirections:0
                            animated:YES];
    }
    
    -(void) slideAnimation:(UIView*) view{
        [view setCenter:CGPointMake(view.center.x,view.center.y+300)];
        [UIView beginAnimations:nil context:NULL];
        [UIView setAnimationDuration:0.15];
        view.center = CGPointMake(view.center.x,view.center.y-300);
        [UIView commitAnimations];
    }
    
    
    -(void) didRotate:(NSNotification*)notification{
        [self centerViewForOrienation];
    }
    
    -(void)centerViewForOrienation{
        UIInterfaceOrientation  interfaceOrientation =   [[UIApplication sharedApplication] statusBarOrientation];
        CGSize fullScreenSize = [[UIScreen mainScreen] bounds].size;
    
        if(interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown ||
           interfaceOrientation == UIInterfaceOrientationPortrait) {
            [animatingView setCenter:CGPointMake(fullScreenSize.width/2,
                                                 fullScreenSize.height/2)];
    
            [self setPopoverContentSize:fullScreenSize];
            [blackTranslucentBackGround setFrame:CGRectMake(0,0,fullScreenSize.width,fullScreenSize.height)];
        }else{
            [animatingView setCenter:CGPointMake(fullScreenSize.height/2,
                                                 animatingView.frame.size.height/2 + 20)];
    
            [self setPopoverContentSize:CGSizeMake(fullScreenSize.height, fullScreenSize.width)];
            [blackTranslucentBackGround setFrame:CGRectMake(0,0,fullScreenSize.height,fullScreenSize.width)];
        }
    }
    
    
    @end
    

    Utility method for topmostview controller

    + (UIViewController*) topMostController
    {
        UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController;
    
        while (topController.presentedViewController) {
            topController = topController.presentedViewController;
        }
    
        return topController;
    }
    

    Usage: I create a popover view controller in story board and send it then used the class as follows:

     popOverViewController = [[AnimatedPopoverController alloc] initWithViewControllerContent:changePhotoViewController];
        [popOverViewController presentPopover];