45

I am trying to display a modal view controller as a UIPresentationFormSheet. The view appears, but I can't seem to resize it. My XIB has the proper height & width, but it seems to get overridden when I call it like this:

composeTweetController = [[ComposeTweet alloc] initWithNibName:@"ComposeTweet" bundle:nil];
composeTweetController.modalPresentationStyle = UIModalPresentationFormSheet;
[self presentModalViewController:composeTweetController animated:TRUE];

Any thoughts? I am using the iPhone SDK 3.2 beta 4

Max MacLeod
  • 26,115
  • 13
  • 104
  • 132
Sheehan Alam
  • 60,111
  • 124
  • 355
  • 556
  • The beta is under NDA, so I doubt you'll get many answers here. I recommend using Apple's SDK 3.2 Beta forums at http://devforums.apple.com – Martin Gordon Mar 16 '10 at 20:43

13 Answers13

91

You are able to adjust the frame of a modal view after presenting it:

Tested in iOS 5.1 - 7.1

MyModalViewController *targetController = [[[MyModalViewController alloc] init] autorelease];
targetController.modalPresentationStyle = UIModalPresentationFormSheet;
targetController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;  //transition shouldn't matter
[self presentViewController:targetController animated:YES completion:nil];

if(floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_6_1){
     targetController.view.superview.frame = CGRectInset(targetController.view.superview.frame, 100, 50);
}else{
     targetController.view.frame = CGRectInset(targetController.view.frame, 100, 50);
     targetController.view.superview.backgroundColor = [UIColor clearColor];
}
Brody Robertson
  • 8,506
  • 2
  • 47
  • 42
  • YES! Thanks! The trick seems to be to resize it after presenting it. – Krumelur Dec 30 '10 at 09:54
  • 6
    It works also for me on iPad, but... If I rotate the device, the view is not centered – Mauro Delrio Aug 25 '11 at 17:56
  • 4
    @MauroDelrio To make it work correctly from landscape you need to flip the center coordinates. ex: CGPoint center = self.view.center; targetController.view.superview.center = {isPortrait} ? center : CGPointMake(center.y, center.x); – Nate Weiner Jan 06 '12 at 01:36
  • 3
    Careful for this approach, it causes some distortion in the view controller's views as a result of the scaling. – Ralphleon Feb 07 '12 at 06:18
  • This approach works for resizing, but messed up subview autoresizing from IB, because resizing is done after view is presented. I have another solution that works below. – Jon Oct 02 '12 at 22:53
  • If you get blurring change the size by 1 pixel, the pixel sizes must be even in both dimensions. If its odd, when its centered it halfs the odd pixel and you get blur. – Chris Mitchelmore Dec 09 '12 at 12:33
  • @bdrober, thanks for your solution, it was helpful. BTW, you are missing a "C" in the last line of your solution, "GPointMake" needs to be "CGPointMake". – AddisDev Jun 06 '13 at 19:26
  • 1
    Nice solution. I prefer changing the bounds like so `targetController.view.superview.frame = CGRectInset(targetController.view.superview.frame, 110, 70);` – stigi Aug 08 '13 at 09:44
  • If I'm using a storyboard, does the above solution require that I not have a segue wired up to my modal from the view controller that calls it? Does this have to all be in code? – Clifton Labrum Jan 02 '14 at 03:54
  • Also, if someone that has this working could spin up a sample project, I'd be forever in your debt. :) – Clifton Labrum Jan 02 '14 at 03:57
  • 2
    need solution for IOS7 – Codesen Jan 02 '14 at 08:28
  • Not an ideal solution. Because the resizing takes place after presenting, it means that if you present with the animation flag YES, the user sees an incorrectly sized UIModalPresentationFormSheet animating in - most likely with misaligned content - followed by a "snap" as the completion block alters the superview size. – Max MacLeod Jun 11 '14 at 19:21
  • @Max Have you actually observed the "snap" after animation? I have never observed this while animating the presentation. – Brody Robertson Jun 11 '14 at 20:47
  • @Brody yes have seen it. I mean it makes sense that it would happen as there's a frame change at the end of the animation. So you get the default form sheet size and animation - takes a split second - that then completes at which point there is an instant frame change. I'd guess the only way around it would be a custom view controller animation. – Max MacLeod Jun 12 '14 at 07:25
  • @Max I am observing the frame change is updating the animation targets. The presented view is animated into view to the appropriate frame location AND dimensions. I just updated that answer for iOS 7, that may have been the cause of the issue. – Brody Robertson Jun 12 '14 at 15:38
  • 1
    @Brody But this solution seems not work in iOS8. My viewcontroller is enclosed inside a nav controller.It worked till iOS7. – Ilanchezhian Nov 01 '14 at 03:22
13

Here's a method that works on iOS7 as well as iOS5 and iOS6: (arc)

-(void)presentController:(UIViewController*)controller fromRootController:(UIViewController*)rootController withSize:(CGSize)size
{
    UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:controller];
    nav.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
    nav.modalPresentationStyle = UIModalPresentationFormSheet;
    [rootController presentModalViewController:nav animated:YES];
    if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0)
    {
        nav.view.superview.backgroundColor = [UIColor clearColor];
        nav.view.bounds = CGRectMake(0, 0, size.width, size.height);
    }
    else
    {
        nav.view.superview.bounds = CGRectMake(0, 0, size.width, size.height);
    }
}
psy
  • 2,791
  • 26
  • 26
  • 1
    This works for me on iOS 7, thank you. I'm getting a deprecation warning on `[rootController presentModalViewController:nav animated:YES];` stating that `presentModalViewController` is no longer supported as of iOS 6. I think the new method is `presentViewController`. Thanks again, nice work. – Clifton Labrum Jan 03 '14 at 04:37
  • Working solution for changing the size under both iOS versions. – Nikolay Spassov Feb 11 '14 at 13:45
  • if the new size larger than the old one and I have clickable items in that area, they will not be clickable anymore... How do I resolve it? – Nava Carmon Jul 15 '14 at 20:11
12

composeTweetController = [[ComposeTweet alloc] initWithNibName:@"ComposeTweet" bundle:nil];
composeTweetController.modalPresentationStyle = UIModalPresentationFormSheet;
[self presentModalViewController:composeTweetController animated:TRUE];
//if you want to change its size but the view will remain centerd on the screen in both portrait and landscape then:
composeTweetViewController.view.superview.bounds = CGRectMake(0, 0, 320, 480);
//or if you want to change it's position also, then:
composeTweetViewController.view.superview.frame = CGRectMake(0, 0, 320, 480);
Skullhouseapps
  • 498
  • 1
  • 7
  • 14
11

As of iOS7 you can simply do

composeTweetController.preferredContentSize = CGSizeMake(380.0, 550.0);
Ed Filowat
  • 404
  • 5
  • 8
  • This is the right approach. Even in the documentation it states: "To provide a custom content size, use the modal view controller’s preferredContentSize property." – JPetric Nov 08 '22 at 15:25
4

Tested and works for iOS 6, using XCode 4.5

I stumbled upon my answer after reading much of the tips on here:

  1. In the viewWillAppear:(BOOL)animated method:

    [super viewWillAppear:animated];
    
     //resize modal view
     self.view.superview.bounds = CGRectMake(0, 0, 432, 680);
    
  2. In the viewDidAppear:(BOOL)animated method:

    CGPoint centerPoint = CGPointMake([[UIScreen mainScreen] bounds].size.width/2, [[UIScreen mainScreen] bounds].size.height/2);
    self.view.superview.center = centerPoint;
    

I tried to add the centering code in the same place as the resizing code, but that did not work. For some reason, it only works after the view has appeared on the screen.

I surmise that it has something to do with the way that UIModalPresentationFormSheet works, because when I was stepping through in the LLDB debugger, I noticed that there was a variable _formSheetSize that was still {540, 620}. Go figure.

Jon
  • 7,848
  • 1
  • 40
  • 41
  • 2
    The problem with this solution is the sheet changing its center after transitionStyle is completed – Fede Cugliandolo Nov 27 '12 at 18:03
  • 1
    @FedeCugliandolo - You are correct. The above method only works if you use a cross fade transition style, or don't animate at all. I ended up presenting with no animation, then using my own animation. – Jon Dec 07 '12 at 13:26
  • Does not work for me :( The form sheet has still the same size – Petr Peller Jan 24 '13 at 14:01
  • 1
    On iOS7 UIModalTransitionStyleCoverVertical is bugged too! But using UIModalTransitionStyleCrossDissolve works fine – Carlos Ricardo Aug 23 '13 at 14:10
4

This will work with any UIModalTransitionStyle

@interface BaseDialog ()

@property(nonatomic,assign) CGRect origFrame;

@end

@implementation BaseDialog

-(void)viewDidLoad{
    [super viewDidLoad];
    self.origFrame=self.view.frame;
}
-(CGSize)formSheetSize{
    return self.origFrame.size;
}
Aran Mulholland
  • 23,555
  • 29
  • 141
  • 228
john07
  • 562
  • 6
  • 16
4

Following first code is how to present your model view controller

 composeTweetController = [[ComposeTweet alloc] initWithNibName:@"ComposeTweet" bundle:nil];
    composeTweetController.modalPresentationStyle = UIModalPresentationFormSheet;
    UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:composeTweetController];
    navigationController.delegate = self;   
    [self presentModalViewController:navigationController animated:YES];

And In your ComposeTweet controller class

-(void)viewWillAppear:(BOOL)animated
{
 [super viewWillAppear:animated];
 self.navigationController.view.superview.frame = CGRectMake(0, 0,500,400);
}
Chathurka
  • 605
  • 6
  • 11
  • +1 - This is the only solution I could find that would respect the x,y coordinates you set. – Lizza Dec 11 '13 at 20:01
3

iOS 7

So the approach of setting the superview's frame or bounds doesn't work anymore on iOS 7 (for UIModalTransitionStyleCoverVertical). You can, however, now set the background color of the superview to clear and then change the frame of the modal view controller how you see fit.

So in iOS 7 you will want to:

  1. present the view controller (presentation mode: UIModalPresentationFormSheet)
  2. set view controller superview background color to clear
  3. change frame of view controller as desired (perhaps making it smaller and then centering it in superview)
Spencer Hall
  • 3,739
  • 1
  • 18
  • 8
  • Centring the view within the superview is not required. Simply setting the bounds (after `-presentViewController:animated:completionHandler`) to `(0, 0, width, height)` causes it to automatically centre itself. – colincameron Mar 20 '14 at 14:15
  • Setting the bounds worked fine for me without using the background color also. (My view controller is in a navigation controller. Not sure if that matters here.) – arsenius May 08 '14 at 04:29
2

I got a full screen modal view from UIPresentationFormSheet with just this line:

modalViewController.view.superview.bounds = CGRectMake(0, 0, 1024, 748);
MRD
  • 7,146
  • 1
  • 21
  • 21
2

@bdrobert sadly your nice solution does not work anymore on iOS6 - the container keeps the original size even though the new viewcontroller is embedded with the custom size.

You probably need to use the containment API introduced in iOS5, but you need to add a dimmed background on your own, fetching all touch events for that area.

Nelson
  • 49,283
  • 8
  • 68
  • 81
  • @Austin: I have used the containment API recently, but not for this purpose. For me going back to the original size is acceptable. – Oliver Michalak Oct 22 '12 at 17:25
  • This is the best solution I see here. Modifying a view's superview's size, whether it be by changing the bounds or the frame, is just asking for trouble. It assumes implementation-specific knowledge of bits of the view hierarchy that you do not control. – jdc Mar 29 '13 at 19:15
0

On change of orientation, this code work perfect....

settingViewController.modalPresentationStyle = UIModalPresentationFormSheet;

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

    settingViewController.view.superview.frame = CGRectMake(0, 0, 700, 700);

    UIInterfaceOrientation currentOrientation = [self getDeviceOrientation];

    if(currentOrientation == UIInterfaceOrientationPortrait || currentOrientation == UIInterfaceOrientationPortraitUpsideDown)
    {
            CGPoint centerPoint = CGPointMake([[UIScreen mainScreen] bounds].size.width/2, [[UIScreen mainScreen] bounds].size.height/2);
            settingViewController.view.superview.center = centerPoint;
    }
    else
    {
        CGPoint centerPoint = CGPointMake([[UIScreen mainScreen] bounds].size.height/2, [[UIScreen mainScreen] bounds].size.width/2);
        settingViewController.view.superview.center = centerPoint;
    }
Anand Mishra
  • 1,093
  • 12
  • 15
0

The modern ios13 way:

use popover (formsheet and page ignore preferredContentSize)

then set or override preferredContentSize aka Ed Pilowat & Co

Anton Tropashko
  • 5,486
  • 5
  • 41
  • 66
-4

The view size is fixed. You will have to implement things yourself if you want something different.

David Dunham
  • 8,139
  • 3
  • 28
  • 41
  • 1
    It's not incorrect and it is not at odds with your answer. Modifying the view controller's view's superview's frame counts as "something different", in my book. – jdc Mar 29 '13 at 19:11