I am developing an iPad App that will load a webpage in a UIWebView modally when the user is authenticated through a login form. This works great, but when I rotate the device into landscape mode, the webview covers only 75% of the screen:
Here is the code from my login view controller:
// Load storyboard for easy instatiation of the login view controller
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard_iPad" bundle:nil];
WebViewController *webController =
(WebViewController *)[storyboard instantiateViewControllerWithIdentifier:#"WebView"];
// Present the embedded browser in fullscreen.
[webController setModalPresentationStyle:UIModalPresentationFullScreen];
[self presentViewController:webController animated:YES completion: nil];
Are you using constraints or auto-resizing masks? If not, you might want to use them and make sure the web view covers the entire view's frame.
All you gotta do is define the frame of UIWebView for landscape orientation in -shouldAutorotateToInterfaceOrientation method of your WebViewController.
It goes something like this,
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
if(toInterfaceOrientation == UIInterfaceOrientationPortrait)
{
webView.frame = CGRectMake (0, 0 768, 1024);
}
else
{
webView.frame = CGRectMake (0, 0 1024, 768);
}
return YES;
}
Use webView delegates
2.Include this method
(void)webViewDidFinishLoad:(UIWebView *)webView {
[self.webView setFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
}
}
include this one also
(void)willAnimateRotationToInterfaceOrientation: (UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
[self.webView setFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
}
Related
I have a problem with rotating a subview when the device orientation is changed. My situation is:
I have root view controller that is declared in
//in AppDelegate.h
#property MainViewController * myMainViewController;
//in AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.myMainViewController = [[MainViewController alloc] initWithNibName:#"MainViewController" bundle:nil];
CGRect initFrame = CGRectMake(0, 0, [[UIScreen mainScreen] bounds].size.width, [[UIScreen mainScreen] bounds].size.height);
self.window = [[UIWindow alloc] initWithFrame:initFrame];
// Override point for customization after application launch.
[self.window makeKeyAndVisible];
self.window.rootViewController = self.myMainViewController;
return YES;
}
In root view controller, I add a subview programmatically; the initial device orientation is portrait, and the size of my subview is set with frame property value (0, 0, 300, 600).
//in MainViewController.h
#property ContentViewController * mySubViewController;
//in MainViewController.m
-(void)viewDidAppear:(BOOL)animated
{
self.mySubViewController = [[ContentViewController alloc] initWithNibName:#"ContentViewController" bundle:nil];
[self.mySubViewController.view setFrame:CGRectMake(0, 0, 300, 600)];
[self.view addSubview:self.mySubViewController.view];
}
When then device orientation changes, I would like to resize my subview according to the new device orientation. If this is landscape, then I want to set my subview size to (0, 0, 600, 300).
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
if(fromInterfaceOrientation==UIInterfaceOrientationLandscapeLeft || fromInterfaceOrientation==UIInterfaceOrientationLandscapeRight)
{
self.mySubViewController.view.frame = CGRectMake(0, 0, 300, 600);
}
else
{
self.mySubViewController.view.frame = CGRectMake(0, 0, 600, 300);
}
}
But, the result is not what I expect. The size of my subview is a rectangle with a size of about (0, 0, 300, 300). What is the problem?
Query your interface orientation again, instead of predicting what would be the current orientation based on fromOrientation as below,
-(void) didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
if (UIInterfaceOrientationIsPortrait(orientation))
{
//Your portrait
}
else
{
//Your Landscape.
}
}
I have a problem with modalviewcontrollers that I want to represent on iPad screen. If I leave the size as it is, then it's all centred fine. But I have very few info on these views, so I need to resize them.
So, when I resize them, I can't force them to appear in the middle of the screen. Even if I manage to center one of them in one orientation, it's messed up in other one.
Here is my current code:
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:acvc];
[nav setModalPresentationStyle:UIModalPresentationFormSheet];
[nav setModalTransitionStyle: UIModalTransitionStyleCoverVertical];
[[acvc view] setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageNamed:#"main_bg.jpg"]]];
[self presentViewController:nav animated:YES completion:nil];
nav.view.superview.frame = CGRectMake(self.view.bounds.size.width/2 + 175, self.view.bounds.size.height/2 - 125, 350, 250);
// nav.view.superview.center = self.view.window.center;
Would appreciate any help, thank you.
Here's a method that works on iOS7 as well as iOS6 and iOS5 and still allows you to use UIModalTransitionStyleCoverVertical:
-(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);
}
}
Change your last line to the following:
nav.view.superview.bounds = CGRectMake(0, 0, 350, 250);
Stopped working in iOS7, unfortunately.
Only changing ModalTransitionStyle to Dissolve solves the problem. Maybe it's a bug in iOS 7...
in ios 7 you can use :
- (void)viewWillLayoutSubviews
{
[super viewWillLayoutSubviews];
self.view.superview.bounds = CGRectMake(0, 0, width, height);
}
it works.
I'm using a custom animation to present my view controllers. Here's the code:
-(void)launchCustomModal:(id)sender
{
UIButton *buttonClicked = (UIButton *)sender;
int selection;
selection = buttonClicked.tag;
[ticker removeFromSuperview];
ticker = nil;
if (selection == 3)
{
MyViewController *myVC = [[MyViewController alloc]initWithNibName:nil bundle:nil];
modalViewController= [[UINavigationController alloc]initWithRootViewController:myVC];
modalViewController.navigationBarHidden = YES;
[modalViewController setToolbarHidden:YES];
CGRect result = self.view.bounds;
result.origin.y = -result.size.height;
modalViewController.view.frame=result;
[self.view addSubview:modalViewController.view];
[UIView animateWithDuration:.375
animations:^{
modalViewController.view.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
}
completion:^(BOOL finished) {
NSLog(#"Finished");
}];
}
return;
}
I've noticed this method makes for a very laggy transition. If I launch the VC in a normal modal, it works quite smoothly. Also, if I animate just a view independent of a view controller, it also works perfectly smoothly. I'm wondering if there is something about the VC that might be causing it to animate so poorly? If its a symptom of something I'm doing or if view controllers are just not meant to be handled this way, etc. Any input is greatly appreciated. Thanks!
It was the CALayer shadows. removed them and it worked fine.
I have an iPad project structured as:
- AppDelegate
- MainWindow
- View Controller
-- View
The View Controllers .m file loads another view programmatically and positions it on the screen. This view is going to be slid in and out.
I do this:
- (void)viewDidLoad
{
[super viewDidLoad];
CGRect viewRect = CGRectMake(0, 0, 0, 0);
CalculatorView *v = [[[CalculatorView alloc]
initWithFrame:viewRect] autorelease];
[self.view.window addSubview:v];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
v.view.frame = CGRectMake(0, 0, 460, 320);
[UIView commitAnimations];
}
The issue that I am having is that the subview I'm adding here doesnt' seem to have the correct orientation. The project supports ONLY landscape, and launches to landscape. The container view is fine, and it contains some buttons which are fine as well. However this programmatically loaded view is stuck in Portrait mode. I have provided the following auto-rotation code (In the loaded view's .m):
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationLandscapeLeft || interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}
But it never gets called.
So, how can I get the programmatically added subview to load in landscape and NOT portrait mode?
TIA!
The UIView class does not receive orientation change messages.
(specially the shouldAutorotateToInterfaceOrientation method, which is a UIViewController Method)
http://developer.apple.com/library/ios/#documentation/uikit/reference/UIViewController_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40006926-CH3-SW23
You will have to manually add a method in your view to inform it that the orientation has changed and you should call this method in your controller shouldAutorotateToInterfaceOrientation method.
To do that you will have to create a reference to you view in your controller and take care of the memory yourself.
#interface MyController : UIViewController {
CalculatorView *_calculatorView;
}
#end
#implementation MyController
- (void)viewDidLoad
{
[super viewDidLoad];
CGRect viewRect = CGRectMake(0, 0, 0, 0);
//inits _calculatorView without the autorelease. Will be released in the dealloc method
_calculatorView = [[CalculatorView alloc]
initWithFrame:viewRect];
[self.view.window addSubview:v];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
_calculatorView.view.frame = CGRectMake(0, 0, 460, 320);
[UIView commitAnimations];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
//calls custom interface orientation method
[_calculatorView MyInterfaceChangedCustomMethod:interfaceOrientation];
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationLandscapeLeft || interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}
-(void) dealloc {
[_calculatorView release];
[super dealloc];
}
#end
EDIT: If you CalculatorView is simple and all you need is to change its frame properly after the device rotation, I think the best approach would be using you view's autoresizingMask similar to the following
_calculatorView = [[CalculatorView alloc]
initWithFrame:viewRect];
_calculatorView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
I am interested to know on how I can resize the view when using UIModalPresentationFormSheet of modalPresentationStyle, it looks like it has a fixed size so I was wondering if anyone out there did managed to manipulate the popup view from the sizing perspective.
So there is either UIModalPresentationFormSheet with a fixed view size or full views and I am after something in between.
MyModalViewController *targetController = [[[MyModalViewController alloc] init] autorelease];
targetController.modalPresentationStyle = UIModalPresentationFormSheet;
targetController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:targetController animated:YES];
// it is important to do this after presentModalViewController:animated:
targetController.view.superview.bounds = CGRectMake(0, 0, 200, 200);
You are able to adjust the frame of a modal view after presenting it:
Tested in iOS 5.1 - 6.1, using XCode 4.62
MyModalViewController *targetController = [[[MyModalViewController alloc] init] autorelease];
targetController.modalPresentationStyle = UIModalPresentationFormSheet;
targetController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal; //transition shouldn't matter
[self presentModalViewController:targetController animated:YES];
targetController.view.superview.frame = CGRectMake(0, 0, 200, 200);//it's important to do this after presentModalViewController
targetController.view.superview.center = GPointMake(roundf(self.view.center.x), roundf(self.view.center.y));//self.view assumes the base view is doing the launching, if not you might need self.view.superview.center etc.
Update The preferred iOS 6.0 view controller presentation method also works correctly:
- (void)presentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)flag completion:(void (^)(void))completion
In ios8 and earlier works:
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.
For iOS 8, simply implement the delegate method (CGSize)preferredContentSize on each view controller. It should resolve all the size issue.
Just to extent Fatos solution (great one)
If your are creating the view controller using a .xib file after the alloc initWithNibName you could store the view frame:
CGRect myFrame = targetController.view.frame;
...
targetController.view.superview.bounds = myFrame;
And then use it for superview.bounds, so the view's size in the .xib will be used and you could change the size more visually.
I put this code in the form sheet view controller:
-(void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.view.superview.bounds = CGRectMake(0, 0, 540, 500); // your size here
}
Note that the resizing occurs early enough that the the presentation animation looks correct.