How to resize a UIModalPresentationFormSheet? - iphone

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

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

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

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

As of iOS7 you can simply do
composeTweetController.preferredContentSize = CGSizeMake(380.0, 550.0);

Tested and works for iOS 6, using XCode 4.5
I stumbled upon my answer after reading much of the tips on here:
In the viewWillAppear:(BOOL)animated method:
[super viewWillAppear:animated];
//resize modal view
self.view.superview.bounds = CGRectMake(0, 0, 432, 680);
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.

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

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

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:
present the view controller (presentation mode: UIModalPresentationFormSheet)
set view controller superview background color to clear
change frame of view controller as desired (perhaps making it smaller and then centering it in superview)

I got a full screen modal view from UIPresentationFormSheet with just this line:
modalViewController.view.superview.bounds = CGRectMake(0, 0, 1024, 748);

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

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

The modern ios13 way:
use popover (formsheet and page ignore preferredContentSize)
then set or override preferredContentSize aka Ed Pilowat & Co

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

Related

iOS7 View moves under status/nav bars when loadView called again

I have a View Controller that creates its view programatically through the loadView method. The purpose of the view is to display a data models contents. When the view loads it is aligned correctly under the status and navigation bar.
But at a later point I present another view modally to allow the user to select a different data model to populate the view. This causes the the loadView to get called again and re-create the required UI for the new data model. The problem is that the view's contents now appear under the status and navigation bars!
Please note that I am not using auto-layout due to having to support iOS4 :( Also if I include the extendedLayout fix - it does fix the problem but only after the modal's dismiss animation completes leaving a jump down effect. My code below, thanks for any help.
- (void)loadView {
CGRect frame = CGRectMake(0, 0, [Constants ScreenWidth], [Constants ScreenHeight] - StatusBarHeight - ToolbarHeight);
self.view = [[UIView alloc] initWithFrame:frame];
self.view.autoresizingMask = UIViewAutoresizingFlexibleHeight;
self.view.autoresizesSubviews = YES;
self.view.backgroundColor = [Constants categoriesScreenBackgroundColor];
CGRect scrollFrame = CGRectMake(0, 0, [Constants ScreenWidth], [Constants ScreenHeight] - StatusBarHeight - ToolbarHeight - ToolbarHeight);
UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:scrollFrame];
scrollView.autoresizingMask = UIViewAutoresizingFlexibleHeight |
UIViewAutoresizingFlexibleBottomMargin |
UIViewAutoresizingFlexibleTopMargin;
[self.view addSubview:scrollView];
_toolbarViewController = [self createToolbarViewController];
[self.view addSubview:_toolbarViewController.view];
_toolbarViewController.productInfoWorkflowState = _productInfoWorkflowState;
UIView *containerView = [[UIView alloc] initWithFrame:scrollView.frame];
containerView.backgroundColor = [UIColor clearColor];
_headerViewController = [self createHeaderViewController];
[containerView addSubview:_headerViewController.view];
_menuViewController = [[ProductInfoMenuViewController alloc] initWithBatch:[self batchData]];
_menuViewController.delegate = self;
[containerView addSubview:_menuViewController.view];
CGRect categoriesFrame = _menuViewController.view.frame;
categoriesFrame.origin.y = _headerViewController.view.frame.size.height;
_menuViewController.view.frame = categoriesFrame;
CGRect viewFrame = containerView.frame;
viewFrame.size.height = _headerViewController.view.frame.size.height + _menuViewController.view.frame.size.height;
containerView.frame = viewFrame;
[scrollView addSubview:containerView];
scrollView.contentSize = containerView.frame.size;
_starViewController = [[StarViewController alloc] initForProduct:_productData With:[StarredItems new]];
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:_starViewController.view];
}
Screen layout after first load:
Screen layout after second load:
With Leo's suggested fix, the scrollView is correct BUT the toolbar at the bottom now appears incorrectly. Code I used (placed after the toolbar creation code above):
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"7.0")) {
self.automaticallyAdjustsScrollViewInsets = NO;
scrollView.scrollIndicatorInsets = UIEdgeInsetsMake(64.0f, 0.0f, 0.0f, 0.0f);
scrollView.contentInset = UIEdgeInsetsMake(64.0f, 0.0f, 0.0f, 0.0f);
}
Results:
Add following code its work for me for same issue, may be its help you
/* ios 7 Change */
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7)
{
self.edgesForExtendedLayout = UIRectEdgeNone;
self.automaticallyAdjustsScrollViewInsets = NO;
}
Does this only happen on iOS 7?
Give this a try:
self.navigationController.navigationBar.translucent = NO;
Try following:
Toolbar.autoresizingMask = UIViewAutoresizingFlexibleTopMargin;
try this
CGRect frame = CGRectMake(0, StatusBarHeight, [Constants ScreenWidth], [Constants ScreenHeight] - StatusBarHeight - ToolbarHeight);
self.view = [[UIView alloc] initWithFrame:frame];
self.view.autoresizingMask = UIViewAutoresizingFlexibleHeight;
self.view.autoresizesSubviews = YES;
self.view.backgroundColor = [Constants categoriesScreenBackgroundColor];
CGRect scrollFrame = CGRectMake(0, StatusBarHeight, [Constants ScreenWidth], [Constants ScreenHeight] - StatusBarHeight - ToolbarHeight - ToolbarHeight);
UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:scrollFrame];
scrollView.autoresizingMask = UIViewAutoresizingFlexibleHeight |
UIViewAutoresizingFlexibleBottomMargin |
UIViewAutoresizingFlexibleTopMargin;
[self.view addSubview:scrollView];
I think the problem is due to incorrect automatic set of content insets of the scrollview.
Try the following. In your loadView, set self.automaticallyAdjustsScrollViewInsets to NO (only if NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_6_1). Now, set the contentInset and scrollIndicatorInsets to the correct values depending on OS version:
scrollview.contentInset = scrollview.scrollIndicatorInsets = UIEdgeInsetMake(NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_6_1 ? 0 : 64, 0, 0, 0);
My problem was solved unmarking the check "Adjust Scroll View Insets" in the View Controller (using Storyboards).

UIImagePickerController overlayView and showsCameraControls issue

I'm trying to use a custom overlay on the UIImagePickerController and also be able to move and scale the resulting image. The problem is when I set showsCameraControls=YES, the overlay won't show but I can use the the move and scale functionality. However, when showsCameraControls=NO, the overlay appears, but when I take the picture, I don't even get the option to crop the image. The actual view loaded from the xib is just a UIToolbar with two buttons, one of which takes the picture
I have a controller (OverlayViewController) which loads the overlay from a xib file as it's view. This controller also has a UIImagePickerController so it sets the overlay of the UIImagePickerController to the view of the OverlayController. This first method is called in a different controller to set it all up and display it. In summary, I need to be able see the overlayView and use it's button to take the picture, which I can then move and scale
-(void) openCameraForImage
{
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])
{
self.overlayViewController =
[[OverlayViewController alloc] initWithNibName:#"OverlayViewController" bundle:nil];
// as a delegate we will be notified when pictures are taken and when to dismiss the image picker
self.overlayViewController.delegate = self;
[self.overlayViewController setupImagePicker:UIImagePickerControllerSourceTypeCamera];
[self presentModalViewController:self.overlayViewController.imagePickerController animated:YES];
}
else {
[Common ShowAlert:#"Alert" andMessage:#"There is no camera on this device"];
}
}
This method is in OverlayViewController and does the work of setting up the Overlay.
- (void)setupImagePicker:(UIImagePickerControllerSourceType)sourceType
{
self.imagePickerController.sourceType = sourceType;
[self.imagePickerController setAllowsEditing:YES];
if (sourceType == UIImagePickerControllerSourceTypeCamera)
{
// user wants to use the camera interface
//
self.imagePickerController.showsCameraControls = NO; //This line allows overlay to show but move and scale doesn't work
self.imagePickerController.allowsEditing = YES;
//[self.view setUserInteractionEnabled:NO];
if ([[self.imagePickerController.cameraOverlayView subviews] count] == 0)
{
// setup our custom overlay view for the camera
//
// ensure that our custom view's frame fits within the parent frame
CGRect overlayViewFrame = self.imagePickerController.cameraOverlayView.frame;
CGRect newFrame = CGRectMake(0.0,
CGRectGetHeight(overlayViewFrame) -
self.view.frame.size.height - 10.0,
CGRectGetWidth(overlayViewFrame),
self.view.frame.size.height + 10.0);
self.view.frame = newFrame;
self.imagePickerController.cameraOverlayView = self.view;
}
}
}
This method in OverlayViewConroller takes the picture
- (IBAction)takePhoto:(id)sender
{
[self.imagePickerController takePicture];
}
I think you can put your image picker code in openCameraForImage
In your OverlayViewController, just use it to purely show the Overlay for your camera.
#implementation RiskCameraOverlayViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
[self.view setBackgroundColor:[UIColor blackColor]];
opUpImage = [UIImage imageNamed:#"camera_overlay_op_up"];
opDownImage = [UIImage imageNamed:#"camera_overlay_op_down"];
opUpFrameBegin = CGRectMake(0, -50, 320, 358);
opUpImageView = [[UIImageView alloc] initWithFrame:opUpFrameBegin];
[opUpImageView setImage:opUpImage];
opDownFrameBegin = CGRectMake(0, 265, 320, 314);
opDownImageView = [[UIImageView alloc] initWithFrame:opDownFrameBegin];
[opDownImageView setImage:opDownImage];
[self.view addSubview:opUpImageView];
[self.view addSubview:opDownImageView];
}
You might reach an issue where "Use photo" or "Retake" is not working, do a
[self.view removeFromSuperview];

uiwindow landscape mode problem

i a uiview compenent and add it to application uiwindow like below. it works fine in portrait mode but when i oriante into lanscape mode it does not work properly. it think uiwindow still feels itself in portrait mode although not. how can run in landscape mode?
thanks.
MyView* popupView = [[MyView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)
url:url slidingType:slidingType html5Flag:_html5Flag];
// i change frame to CGRectMake(0, 0,480, 320) but not works
[popupView setTitle:self.currentAd.altText];
popupView.backgroundColor = [UIColor colorWithWhite:0.0 alpha:0.5];
UIWindow* mainWindow = (((UIWindow*) [UIApplication sharedApplication].delegate).window);
CGPoint middleCenter = popupView.center;
CGSize offSize = [UIScreen mainScreen].bounds.size;
CGPoint offScreenCenter = CGPointMake(offSize.width / 2.0, offSize.height * 1.5);
popupView.center = offScreenCenter;
[mainWindow addSubview:popupView];
popupView.center = middleCenter;
Is that you view popupView autorized to rotate ? You need yo implement this method in your UIViewController class:
- (void)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
return YES;
}

Landscape Screen shifted to right in 20px

I am trying to rotate the screen on the iphone. For example,
First state of screen : is "Portrait".
Then it calls "Landscape" screen. Following code is used for making Landscape screen :
- (void)viewDidLoad {
[super viewDidLoad];
[UIApplication sharedApplication].statusBarOrientation = UIInterfaceOrientationLandscapeRight;
CGFloat angle = 90 * M_PI / 180;
self.view.transform = CGAffineTransformMakeRotation(angle);
self.view.center = [nRangeAppDelegate sharedAppDelegate].window.center;
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 20, 480, 44)];
label.textAlignment = UITextAlignmentLeft;
label.numberOfLines = 2;
label.text = #"12345\n67890";
[self.view addSubview:label];
}
But above code shifted to right in 20 px.
How to make 480x320 view at point 0,0 no shifting ?
Thanks in advance.
Update:
My application navigation based application. All UIViewControllers have one UIView. When call the the view I am trying rotate, this code is used : MyRoratedController *myCtrlr = [[MyRoratedController alloc] initWithNibName:#"MyRoratedController" bundle:nil]; [navigationController pushViewController: myCtrlr animated:NO]; I've changed CGPointMake(160.0, 240.0) by many different values. But no changes.
Your window is shifted because the appDelegate window is not centred on the screen as it is drawn below the status bar
Try this:
self.view.center = CGPointMake(160.0, 240.0);
You must make sure you are adding this view to a normal viewcontroller (ie not a nav controller or similar). The easiest way to do this is to add it to the main application window, like so:
MyRoratedController *myCtrlr = [[MyRoratedController alloc]
initWithNibName:#"MyRoratedController" bundle:nil];
[window addSubview:[myCtrlr view]];
Note that if your app has a status bar shown you will have to change the 160 above to 150

Setting the size of a UIView

I have a UIViewController subclass to control a UIView that I want to add to a UIScrollView. I only want the view to be 100px high, but when I add it to the scroll view it gets made 460px high, ignoring the frame size I set:
MyViewController *vc = [[MyViewController alloc] init];
vc.view.frame = CGRectMake(0, 0, 320, 100);
myScrollView.autoresizesSubviews = NO
[myScrollView addSubview:vc.view];
[vc release];
I have set the scroll view to not autoresize subviews but it seems this is still happening! What can I do?
I have also tried setting the frame size inside loadView: in the UIViewController (which is where I will add all my controls and will need access to the size of the view) but that doesnt work either!
- (void)loadView {
[super loadView];
self.view.backgroundColor = [UIColor redColor];
self.view.frame = CGRectMake(0, 0, 320, 100); // still doesnt work
}
Any help would be greatly appreciated!
You are using loadView incorrectly, im even suprised you see a view (you shouldnt since in load view you arent assigns the vc view to anything), in loadView you must assign your view to a new UIView i nstance, anyway, you should be doing the same but in viewDidLoad instead of load view, that might work for you
Here is a snippet of how I do it. Note that the origin is with respect to the view you are adding to (in my case 'self').
appRect.origin=CGPointMake(0.0, 0.0);// origin
appRect.size = CGSizeMake(320.0f, 100.0f); //size
CGRect frame = CGRectInset(appRect, 0.0f, 0.0f);
gv=[[GraphicsView alloc] initWithFrame:appRect object:[model me]];
[gv setFrame:frame];
[self.view addSubview:gv];
[gv release];