iPad custom size of modal view controller

IpadUiviewcontrollerModalviewcontroller

Ipad Problem Overview


I have a couple of modal view controllers of certain size. I'm trying to avoid the use of custom views (creating full screen black translucent overlay over current view, add the modal view over that view, do the animations, etc) to present it because there is no modalPresentationStyle that fits the size of my controllers.

Now I'm using UIModalPresentationPageSheet but my view is smaller in height and I have an ugly blank space

Desired presentation

 _______________
|    _______    |
|   |       |   |
|   |  MyVC |   |
|   |       |   |
|    -------    |
 --------------- 

Actual presentation

 _______________
|   |       |   |
|   |  MyVC |   |
|   |       |   |
|   |-------|   |
|   | blank |   |
 ---------------    

If I use the UIModalPresentationFormSheet the container is smaller in width.

I'm trying to figure out how to do it but I don't know if it's possible. What is the solution to the problem of presenting a modal VC smaller than any of the presentationStyles? The only solution is to arrange a "custom modal view controller engine"? Popovers doesn't fit my design requirements :(

Ipad Solutions


Solution 1 - Ipad

As some other users here, I also had the problem that the origin of the modal view controller was not correct. After some experiments, I found a solution that worked for me:

- (void)viewWillLayoutSubviews{
    [super viewWillLayoutSubviews];   
    self.view.superview.bounds = CGRectMake(0, 0, <width>, <height>);
}

Solution 2 - Ipad

I obtained the following result (link text) by using:

self.modalPresentationStyle = UIModalPresentationFormSheet;

and by presenting it as a modal view controller. Let me know if you need further help.

Solution 3 - Ipad

All these answers will not work on ios8 SDK.

This will work:

AboutViewController * _aboutViewController = [[AboutViewController alloc] init];
    _aboutViewController.modalPresentationStyle = UIModalPresentationFormSheet;
    if(IS_IOS8)
    {
        _aboutViewController.preferredContentSize = CGSizeMake(300, 300);
    }
    [self presentViewController:_aboutViewController animated:YES completion:nil];

In AboutViewController.m

- (void)viewWillLayoutSubviews{
    [super viewWillLayoutSubviews];
    
    if(!IS_IOS8)
    {
        self.view.superview.bounds = CGRectMake(0, 0, 300, 300);
    }
}

IS_IOS8

#define IS_IOS8 ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8)

In iOS 8 you can also use UIPresentationController which gives you more customization options.

Solution 4 - Ipad

I had an issue getting the custom sized modal to center until I figured out what ViewController.view.superview.frame was set to initially. It is determined based on the UIModalPresentation type. superview.center isn't even needed(as far as my testing shows).

Also, I set the coordinates dynamically using [UIScreen mainScreen].applicationFrame, only supporting landscape orientation for now. You have to do a conditional check to support both portrait and landscape by flipping the X/Y and Height/Width values.

Here was my first working solution for iOS 6.0:

ViewController.modalPresentationStyle = UIModalPresentationFormSheet;
ViewController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentViewController:ViewController animated:YES completion:nil];
ViewController.view.superview.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin;
ViewController.view.superview.frame = CGRectMake(
                                                                    // Calcuation based on landscape orientation (width=height) 
                                                                    ([UIScreen mainScreen].applicationFrame.size.height/2)-(320/2),// X
                                                                    ([UIScreen mainScreen].applicationFrame.size.width/2)-(320/2),// Y
                                                                    320,// Width
                                                                    320// Height
                                                                    );

And then I looked at the previous answer and face palmed. Shortens my solution a tad by replacing the last line with:

ViewController.view.superview.bounds = CGRectMake(0, 0, 320, 320);

EDIT for final solution and remarks.

Solution 5 - Ipad

The best way to do this is to change the bounds property on the superview of the view being presented inside the formsheet. When you present a view modally, the presented view is embedded inside another view.

You should set the bounds property of the superview to the same rect as the view's bounds. First add a private ivar in your class:

@implementation MySpecialFormsheet {
    CGRect _realBounds;
} 

It's best to do this in viewWillAppear:. Add the following code to the view controller that is being presented modally:

- (void)viewWillAppear:(BOOL)animated {
	[super viewWillAppear:animated];
	self.view.superview.bounds = _realBounds;
}

You need to cache _realBounds in your viewDidLoad method:

- (void)viewDidLoad {
	_realBounds = self.view.bounds;
	[super viewDidLoad];
}

Solution 6 - Ipad

even for reducing the forma sheet height and width you can use

[self.view.superview setBounds:CGRectMake(0, 0, 450, 480)];

Solution 7 - Ipad

This is my solution for a NOT autolayout view (never tried with autolayout) and compliant with iOS 7 and iOS 8.

At first be sure to call the modal view in this way:

CloudSettingsViewController *cloudController = [[CloudSettingsViewController alloc] initWithNibName:@"CloudSettingsView" bundle:nil];
    
CGRect originalBounds = cloudController.view.bounds;
    
cloudController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
cloudController.modalPresentationStyle = UIModalPresentationFormSheet;

[self presentViewController:cloudController animated:YES completion:nil]; 

With iOS 8 set the preferredContentSize in the viewDidLoad method of the modal view.

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // backup of the original size (selected in interface builder)
    height = self.view.frame.size.height;
    width = self.view.frame.size.width;
    
    if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8) // versioni successive ios 8
        self.preferredContentSize = CGSizeMake(width, height); // this is necessary to get the correct size of the modal view
}

This works ALSO when the modal view needs to display the keyboard on iPad.

With previous versions of iOS 8 you should set the bounds after presentViewController call:

[currentController presentViewController:controlPanelController animated:YES completion:nil];
if ([[[UIDevice currentDevice] systemVersion] floatValue] < 8) 
    cloudController.view.superview.bounds = originalBounds;//it's important to do this after 

Solution 8 - Ipad

The approaches described above need to be tweaked for iOS7:

// set desired bounds, then call -presentFromViewController:

@implementation PresentedViewController
{
    CGRect _presentationBounds;
}

- (void)presentFromViewController:(UIViewController *)viewController
{
    self.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
    self.modalPresentationStyle = UIModalPresentationFormSheet;

    _presentationBounds = self.view.bounds;

    [viewController presentViewController:self animated:YES completion:nil];
}

- (void)viewWillLayoutSubviews
{
    [super viewWillLayoutSubviews];

    if (!CGRectIsEmpty(_presentationBounds))
    {
        self.view.superview.bounds = _presentationBounds;
        _presentationBounds = CGRectZero;
    }
}

(This code also works on iOS6.)

Solution 9 - Ipad

Even I was struggling with the same issue for quite a while. After giving few tries from many of the answers given here I came up with a solution that worked for me pretty well.

Here is the code while presenting the view controller.

    SomeViewController *sovcObj = [[SomeViewController alloc] initWithNibName:@"SyncOptionsViewController" bundle:nil];
someObj.modalPresentationStyle = UIModalPresentationFormSheet;
someObj.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentViewController:someObj animated:YES completion:nil];
someObj.view.superview.bounds = CGRectMake(0, 0, 400, 400); // whatever width and height you want

In the xib (if you are using one) in the 'Simulated Metrics' section select 'Freeform' size.

Apart from this you need to write the below code in your presented view controller (i.e.., SomeViewController in this example)

- (void)viewWillLayoutSubviews{
[super viewWillLayoutSubviews];
self.view.superview.bounds = CGRectMake(0, 0, 400, 400); // whatever width and height you want

}

This code also works for iOS 7 as well

Solution 10 - Ipad

One solution is to use UIModalPresentationPageSheet to present a page sheet and then immediately resize the modal view. This is fully explained in this answer to another question.

Solution 11 - Ipad

Resize the modal view "after" it is presented using presentModalViewController method.See this link to resize modal View <https://coderwall.com/p/vebqaq>

Solution 12 - Ipad

You can use MZFormSheetController like this:

MZFormSheetController *formSheet = [[MZFormSheetController alloc] initWithSize:customSize viewController:presentedViewController];
[presentingViewController mz_presentFormSheetController:formSheet animated:YES completionHandler:nil];

Solution 13 - Ipad

This solution worked for me as I had the same issue.

My modal view structure is the following (I use UIModalPresentationCurrentContext at both presenting and presented controllers to achieve transparency in the presented VC)

ModalViewController
  > UIView (view) - resized to the same size as the presenting controller but has semi-translucent background - done automatically
      >> UIView (contentView) - the true view with the content of the popup - this is the one that got consistently placed at the top of the screen all the time

In ModalViewController I overwrote the following method to fix the positioning issue:

- (void) viewWillLayoutSubviews(){
  [super viewWillLayoutSubviews];

  CGRect r = self.view.bounds();
  self.contentView.center = CGPointMake(r.size.width/2,r.size.height/2);
}

I actually create and size the content view first but in different method.

Hope this helps someone.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionemenegroView Question on Stackoverflow
Solution 1 - IpadLensflareView Answer on Stackoverflow
Solution 2 - IpadmarcioView Answer on Stackoverflow
Solution 3 - Ipadpawel_dView Answer on Stackoverflow
Solution 4 - IpadBrendenView Answer on Stackoverflow
Solution 5 - IpadRob JonesView Answer on Stackoverflow
Solution 6 - IpadKasanameView Answer on Stackoverflow
Solution 7 - IpadMagurizioView Answer on Stackoverflow
Solution 8 - IpadhatfinchView Answer on Stackoverflow
Solution 9 - IpadRajeshView Answer on Stackoverflow
Solution 10 - IpadTravelling ManView Answer on Stackoverflow
Solution 11 - IpadNetDeveloperView Answer on Stackoverflow
Solution 12 - IpadMaxim PavlovView Answer on Stackoverflow
Solution 13 - IpadMoonwalkerView Answer on Stackoverflow