Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iPad custom size of modal view controller

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 :(

like image 402
emenegro Avatar asked Jul 21 '10 10:07

emenegro


12 Answers

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>);
}
like image 182
Lensflare Avatar answered Oct 05 '22 02:10

Lensflare


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.

like image 37
marcio Avatar answered Oct 05 '22 03:10

marcio


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.

like image 40
pawel_d Avatar answered Oct 05 '22 04:10

pawel_d


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.

like image 24
Brenden Avatar answered Oct 05 '22 04:10

Brenden


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];
}
like image 31
Rob Jones Avatar answered Oct 05 '22 03:10

Rob Jones


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

[self.view.superview setBounds:CGRectMake(0, 0, 450, 480)];
like image 26
Kasaname Avatar answered Oct 05 '22 04:10

Kasaname


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 
like image 31
Magurizio Avatar answered Oct 05 '22 04:10

Magurizio


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.)

like image 27
hatfinch Avatar answered Oct 05 '22 03:10

hatfinch


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

like image 30
Rajesh Avatar answered Oct 05 '22 04:10

Rajesh


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.

like image 43
Travelling Man Avatar answered Oct 05 '22 03:10

Travelling Man


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

like image 36
NetDeveloper Avatar answered Oct 05 '22 03:10

NetDeveloper


You can use MZFormSheetController like this:

MZFormSheetController *formSheet = [[MZFormSheetController alloc] initWithSize:customSize viewController:presentedViewController];
[presentingViewController mz_presentFormSheetController:formSheet animated:YES completionHandler:nil];
like image 25
Maxim Pavlov Avatar answered Oct 05 '22 04:10

Maxim Pavlov