ChatGPT解决这个技术问题 Extra ChatGPT

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

It would be nice of you to accept a correct answer to your question by clicking the gray checkmark next to it.

L
Lensflare

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>);
}

This works for me. It correctly centers a resized form sheet in iOS 6.
Works for iOS 7 as well
I would add that, if you need to change the view size multiple times while it is displayed (e.g. expand/collapse), you need to set a class member to hold the CGRect, then on willLayoutSubviews you need to add if( CGRectIsEmpty( myRect ) ) { myRect = CGRectMake( 0, 0, <width>, <height> ); ) } self.view.superview.bounds = myRect; viewWillLayoutSubviews gets called every time you update the superview, so strange things happen if you try to resize it more often than on the initial view load.
@Renexandro doesn't work on iOS7. When I set a rect size, it appears in that size for a second, and flash to the default size.
It doesn't work when you put at least 1 editable UITextField inside the view. When you try to go in editing mode, the framework try to show the keyboard and the sistem goes in an infinite loop !
m
marcio

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.


Thanks for the answer but FormSheet doesn't fits my size (I told in the question).
you can adjust the frame in the viewDidAppear
It works but the shadow is equal to the original frame of the form sheet. But... it's a good approach. Thank you, if no one answer, the bounty is yours ;)
The bad side of this is Apple doesn't document it so... :(
Please review my answer below, it gives you control over the size of the modal.
p
pawel_d

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.


Thanks for sharing the easy way in iOS 8, I just spent 2 hours trying to figure out how to do it and there's nothing in the official doc (now) about this.
Great! Remember that you also can define the preferred content size Interface Builder.
preferredContentSize is working fine for me. But i need to change my position in iOS 8. Which property i have to use?
@VipinVijay I have not tested this, but maybe you can use UIPresentationController UIViewControllerTransitioningDelegate. Check my other answer and try to set frameOfPresentedViewInContainerView: stackoverflow.com/questions/25903412/…
B
Brenden

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.


I usually use the same solution for resizing a modalview. But I realize that it doesn't work for iOS 6. The view always gets stuck at the top of parent view. Any solution?? thanks
I test on an ipad with ios 6 and haven't seen this happen. What are you testing on? Does this solution work if you test it?
my problem is that I can't change the superview's frame origin. it changes the size but not the center. only if I do it on completion block..
Just a guess, may be because its controller is changing it after you change it so it appears as though you can't change it.
A
Alois Holub

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];
}

Hi in my app i used appear new View in the left side not in centre.How can do?
Not sure about earlier versions, but as of iOS 6.0 the view is no longer centered. The x-coordinate always starts where a normal formsheet would. Doesn't seem to be fixable with self.view.center or self.view.superview.center.
@Answerbot I'm not sure what you're trying to say. This technique is working for me on iOS 6.
M
Mick MacCallum

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

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

Man, I still can't believe how easy it is! I was really planning to build my own View to simulate the UIModalViewController effect. Thanx!
M
Magurizio

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 

preferredContentSize is working fine for me. But i need to change my position in iOS 8. Which property i have to use?
@VipinVijay : Did you figure out how to change position in iOS 8 and above?
h
hatfinch

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


R
Rajesh

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


I wish I could upvote this twice. I tried EVERYTHING (about 3 hours of my life dedicated solely to this) until this finally worked. Thank you.
C
Community

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.


N
NetDeveloper

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


Post an answer, not a link.
Basically, The post in the link above suggests to Resize the modal view "after" it is presented using presentModalViewController method.
M
Maxim Pavlov

You can use MZFormSheetController like this:

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

M
Moonwalker

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.


关注公众号,不定期副业成功案例分享
Follow WeChat

Success story sharing

Want to stay one step ahead of the latest teleworks?

Subscribe Now