I have an app that I want to only work with in Landscape.
For the first time ever, I'm foregoing IB and trying to set up all my views programmatically, so I'm creating a view and adding a bunch of subviews in loadView method:
self.view = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
// Create a GMSCameraPosition that tells the map to display the
// coordinate -33.86,151.20 at zoom level 6.
GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:-33.86
longitude:151.20
zoom:6];
self.mapView = [GMSMapView mapWithFrame:CGRectZero camera:camera];
self.mapView.myLocationEnabled = YES;
self.mapView.delegate = self;
self.mapView.mapType = kGMSTypeHybrid;
self.mapView.frame = self.view.frame;
[self.view addSubview:self.mapView];
// add the toolbar
UIToolbar* toolbar = [[UIToolbar alloc] init];
toolbar.frame = CGRectMake(0, self.view.frame.size.height - 44, self.view.frame.size.width, 44);
toolbar.barStyle = UIBarStyleDefault;
NSMutableArray* items = [NSMutableArray array];
[items addObject:[[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:#"location-arrow.png"]
style:UIBarButtonItemStyleBordered
target:self
action:#selector(locateMe:)]];
[items addObject:[[UIBarButtonItem alloc] initWithTitle:#"Tools"
style:UIBarButtonItemStyleBordered
target:self
action:#selector(toolsButtonTapped:)]];
[toolbar setItems:items];
[self.view addSubview:toolbar];
In my project settings, I have disabled both portrait orientations. I also have this in my root view controller:
// Enforce Landscape Orientation
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscape;
}
-(UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationLandscapeRight;
}
My problem is that the simulator starts in landscape mode, but all of the views are sized for portrait - so the bottom chunk of my views are below the screen and the right side of my screen is a big empty region.
I tried fixing this by switching the width and height of the application frame in the first line, but then that leaves some empty vertical room on the left edge of the screen for the status bar.
So, what's the correct way of doing what I'm trying to do?
Instead of using [[UIScreen mainScreen] applicationFrame]
try using [[[[[self view] window] rootViewController] view] bounds]
The bounds will represent the width and height correctly in Landscape orientation, because the bounds will take into account the transform (rotation) that has been applied, while the frame will not.
To see what I mean, set a breakpoint, and in the debugger print out the description of the top level view lldb> po [[[[self view] window] rootViewController] view]
You'll see that the view has a rotation transform and that its frame does not represent the dimensions of the screen in landscape, but represents the dimensions in portrait!
The long way to calculate the correct applicationFrame would be
BOOL iOS7 = NO;
NSString *currSysVer = [[UIDevice currentDevice] systemVersion];
if ([currSysVer compare:#"7.0" options:NSNumericSearch] != NSOrderedAscending)
iOS7 = YES;
CGRect theFrame;
CGRect statusBarFrame = [[UIApplication sharedApplication] statusBarFrame];
CGRect screenBounds = [[UIScreen mainScreen] bounds];
if (UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation])) {
theFrame.origin = CGPointZero;
theFrame.size.width = screenBounds.size.height;
theFrame.size.height = screenBounds.size.width;
if (iOS7 == NO) {
// statusBarFrame will be CGRectZero if not visible, so this is safe
theFrame.size.height -= statusBarFrame.size.width; // because we're in landscape orientation
}
}
else {
theFrame = screenBounds;
if (iOS7 == NO) {
// statusBarFrame will be CGRectZero if not visible, so this is safe
theFrame.size.height -= statusBarFrame.size.height; // because we're in portrait orientation
}
}
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if (UIInterfaceOrientationIsLandscape( interfaceOrientation))
{
return YES;
}
return NO;
}
Put this code Appdelegate .M.....
Put this in current viewcontroller
// ios 5
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if (UIInterfaceOrientationIsLandscape( interfaceOrientation)) {
return YES;
}
return NO;
}
// ios6
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscape;
}
Related
I have an 2 vc,with push from one screen to another screen.In my vc2 programmatically i am adding the nav bar title, bar button . But when i add the view some 10 points from top is reduced. not showing fully. I tried all the possibilities. Attached the image also:
in my vc2 :
- (void)viewDidLoad {
[super viewDidLoad];
_menuView.hidden = YES;
[self navItems];
}
-(void)navItems{
UIImage* filterImage = [UIImage imageNamed:#"filter.png"];
CGRect frameimg = CGRectMake(0,0, 15,15);
filterBtn = [[UIButton alloc] initWithFrame:frameimg];
[filterBtn setBackgroundImage:filterImage forState:UIControlStateNormal];
[filterBtn addTarget:self action:#selector(MenuTap:) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *filter =[[UIBarButtonItem alloc] initWithCustomView:filterBtn];
self.navigationItem.rightBarButtonItem = filter;
self.title = #"Demo";
self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:#"" style:UIBarButtonItemStylePlain target:nil action:nil];
}
- (IBAction)MenuTap:(id)sender
{
_menuView.hidden = NO;
//1
// [self.navigationController.view addSubview:_menuView];
// [self.view addSubview:_menuView];
//2
// UIWindow *window = [[[UIApplication sharedApplication] delegate] window];
// [window addSubview: _menuView];
//
//3
// UIWindow *currentWindow = [UIApplication sharedApplication].keyWindow;
//[currentWindow addSubview:_menuView];
//4
//[[UIApplication sharedApplication].windows.lastObject addSubview:_menuView];
//5
// self.navigationController.navigationBar.layer.zPosition = -1;
//[self.view addSubview:_menuView];
}
But not able to show fully any idea please ?
based on your question in here added the detail answer, if you want to show below the status bar , then you need to get the status bar height initially, there after you need to add the y position how much you need.
- (IBAction)MenuTap:(id)sender
{
_menuView.hidden = NO;
//initially getStatusbar height
float statusBarHeight = [self statusBarHeight];
// assign your subview to window bounds
_menuView.frame = [[UIScreen mainScreen] bounds];
CGRect frameRect = _menuView.frame;
// convert your y- coordinates based on your need
frameRect.origin.y = statusBarHeight;
_menuView.frame = frameRect;
[self.navigationController.view addSubview:_menuView];
}
-(float) statusBarHeight
{
CGSize statusBarSize = [[UIApplication sharedApplication] statusBarFrame].size;
return MIN(statusBarSize.width, statusBarSize.height);
}
I am updating with #Anbu.Karthic solution.
In your (IBAction)MenuTap:(id)sender update the code with below. It will work. I have tried.
- (IBAction)MenuTap:(id)sender
{
_menuView.hidden = NO;
[self.navigationController.view addSubview:_menuView];
_menuView.frame = [[UIScreen mainScreen] bounds];
}
I added a UIScrollView to my main UIViewController but for some reason i can't see anything. I painted the scroll view in grey in order to see the actual size, but all i get is a white screen.
Here is my very simple code:
-(void) viewDidLoad{
[super viewDidLoad];
UIScrollView *scroll;
[scroll setBackgroundColor:[UIColor grayColor]];
CGRect screenRect = [[UIScreen mainScreen] bounds];
_orientation = [UIDevice currentDevice].orientation;
if (UIDeviceOrientationIsPortrait(_orientation)){
scroll.showsHorizontalScrollIndicator = YES;
}else{
scroll.showsVerticalScrollIndicator = YES;
}
scroll = [[UIScrollView alloc] initWithFrame:CGRectMake(screenRect.origin.x,
screenRect.origin.y,
screenRect.size.width,
screenRect.size.height)];
[self.view addSubview:scroll];
}
The view size might change, i'm working on a changing iOS device size.
I am developing an ios application with viewcontroller which has two subviews A) mpmoviecontroller and B) pageviewcontroller. if the player is not in full screen mode and I change orientation subviews alignment is ok (I handle orientation change and make new CGRects for subviews). When I switch my video mode to full screen, rotate to landscape and zoom out, my pageviewcontrollers view is gone out of the screen. Here is my code
- (void)viewDidLoad
{
[super viewDidLoad];
self.streamPlayer.controlStyle = MPMovieControlStyleDefault;
[self.view addSubview: self.streamPlayer.view];
[self.streamPlayer prepareToPlay];
NSURL *streamURL = [NSURL URLWithString:#"http://www.nasa.gov/multimedia/nasatv/NTV-Public-IPS.m3u8"];
[self.streamPlayer setContentURL:streamURL];
[self.streamPlayer play];
self.pageViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"PageViewController"];
[self setFramesForPotrait];
[self addChildViewController:_pageViewController];
[self.view addSubview:_pageViewController.view];
[self.pageViewController didMoveToParentViewController:self];
}
- (void)orientationChanged:(NSNotification *)notification
{
[self adjustViewsForOrientation:[[UIApplication sharedApplication] statusBarOrientation]];
}
- (void) adjustViewsForOrientation:(UIInterfaceOrientation) orientation {
if (orientation == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown)
{
[self setFramesForPotrait];
NSLog(#"%f",[[UIScreen mainScreen] bounds].size.height);
NSLog(#"%f",[[UIScreen mainScreen] bounds].size.width);
}
else if (orientation == UIInterfaceOrientationLandscapeLeft || orientation == UIInterfaceOrientationLandscapeRight)
{
[self setFramesForLandscapeMode];
// self.pageViewController.view.frame = self.pageViewContainterRect;
NSLog(#"%f",[[UIScreen mainScreen] bounds].size.height);
NSLog(#"%f",[[UIScreen mainScreen] bounds].size.width);
}
}
-(void)setFramesForPotrait
{
CGRect frame = [[UIScreen mainScreen] bounds];
_videoFrameRect = CGRectMake(0,_BAR_HEIGHT, frame.size.width,_VIDEO_HEIGHT_PORTRAIT);
_pageViewContainterRect = CGRectMake(frame.origin.x, _BAR_HEIGHT + _VIDEO_HEIGHT_PORTRAIT, frame.size.width, frame.size.height-_BAR_HEIGHT-_VIDEO_HEIGHT_PORTRAIT);
[self.pageViewController.view setFrame :self.pageViewContainterRect ];
[self.streamPlayer.view setFrame: _videoFrameRect];
}
-(void)setFramesForLandscaeMode
{
CGRect frame = [[UIScreen mainScreen] bounds];
_videoFrameRect = CGRectMake(0,_BAR_HEIGHT, frame.size.height/2,frame.size.width-_BAR_HEIGHT);
_pageViewContainterRect = CGRectMake(frame.size.height/2, _BAR_HEIGHT, frame.size.height/2,frame.size.width-_BAR_HEIGHT);
self.pageViewController.view.frame = self.pageViewContainterRect;
[self.streamPlayer.view setFrame: _videoFrameRect];
}
So I roughly followed this tutorial on how to make an iAd banner not cover a Phonegap app, but had to improvise because it didn't really work. So in my webViewDidFinishLoad in my mainViewController method, here is what I have:
- (void)webViewDidFinishLoad:(UIWebView*)theWebView
{
adView.frame = CGRectOffset(adView.frame, 0, [[UIScreen mainScreen] bounds].size.height - 70);
adView.delegate = self;
[adView setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin];
[theWebView addSubview:adView];
[self.view bringSubviewToFront:adView];
return [ super webViewDidFinishLoad:theWebView ];
}
adView has been properly initialized and is functioning properly. What breaks this (as in I can't click the banner) is this code in viewWillAppear:
- (void)viewWillAppear:(BOOL)animated
{
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7)
{
CGRect viewBounds = [self.webView bounds];
viewBounds.origin.y = 20;
viewBounds.size.height = viewBounds.size.height - 70;
self.webView.frame = viewBounds;
}
[super viewWillAppear:animated];
}
I added the 70px offset in order to have the banner not cover the content. Now, if I remove this code, I can click the banner fine. What is wrong?
Silly me. I was adding the subview to theWebView instead of self.view, which made it outside of its boundary and unclickable.
When I launch my universal app on the iPad in landscape mode, the app won't recognize taps or gestures on the side of the screen closest to the home button. I've gone over every similar question on stackoverflow trying to get to the bottom of this but I just can't get it to work.
It would appear that one of the views in the view hierarchy is in portrait rather than landscape but I can't find any views that are incorrectly sized. Also, note that the app works fine when launched in portrait mode and rotates correctly and recognizes all taps after rotation. But when launched in landscape there is always a "dead zone" on one side of the screen where taps are not recognized.
The view hierarchy looks like:
UIWindow (frame: 0, 0, 1024, 768)
UINavigationController
UIViewController
UIView (frame: 0, 0, 1024, 768)
GLView (frame: 0, 0, 1024, 768)
I have checked the frames and bounds for the views, sets clipsToBounds = YES and changed the background colors of them to see if they are not being layed out correctly but they are all occupying the entire screen (1024x768) as intended.
I have subclassed UIWindow and overridden the sendEvent: method and it is NOT being called at all when I tap on the dead zone at the left hand side of the screen. Does this indicate where the problem might lie?
Here is my app delegate where the window is created:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Create the main window
CGRect windowFrame = [[UIScreen mainScreen] bounds];
if (application.statusBarOrientation == UIInterfaceOrientationLandscapeLeft || application.statusBarOrientation == UIInterfaceOrientationLandscapeRight) {
windowFrame = CGRectMake(0, 0, windowFrame.size.height, windowFrame.size.width);
}
window_ = [[MyUIWindow alloc] initWithFrame:windowFrame];
navController_ = [[BFNavigationController alloc] init];
navController_.navigationBarHidden = YES;
// for rotation and other messages
[[CCDirector sharedDirector] setDelegate:navController_];
// set the Navigation Controller as the root view controller
[window_ setRootViewController:navController_];
bfViewController_ = [[BFViewController alloc] init];
[navController_ pushViewController:bfViewController_ animated:NO];
// make main window visible
[window_ makeKeyAndVisible];
return YES;
}
And this is the UIViewController's viewDidLoad method where the UIView is configured:
- (void)viewDidLoad
{
[super viewDidLoad];
UIWindow *mainWindow = (UIWindow*)[UIApplication sharedApplication].windows.firstObject;
self.view.frame = mainWindow.bounds;
self.view.autoresizingMask = UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth;
self.view.autoresizesSubviews = YES;
self.view.clipsToBounds = YES;
[self initCocos2D];
}
And here's where the GLView is created:
- (void)initCocos2D {
UIWindow *window = [[[UIApplication sharedApplication] windows] firstObject];
CCDirector *director = (CCDirectorIOS*) [CCDirector sharedDirector];
CCGLView *glView = [CCGLView viewWithFrame:[window bounds]
pixelFormat:kEAGLColorFormatRGB565
depthFormat:0
preserveBackbuffer:NO
sharegroup:nil
multiSampling:NO
numberOfSamples:0];
glView.clipsToBounds = YES;
[glView setMultipleTouchEnabled:YES];
director.wantsFullScreenLayout = YES;
// set FPS at 60
[director setAnimationInterval:1.0/60];
// attach the openglView to the director
[director setView:glView];
// 2D projection
[director setProjection:kCCDirectorProjection2D];
// Enables High Res mode (Retina Display) on iPhone 4 and maintains low res on all other devices
if( ! [director enableRetinaDisplay:YES] )
CCLOG(#"Retina Display Not supported");
// Default texture format for PNG/BMP/TIFF/JPEG/GIF images
// It can be RGBA8888, RGBA4444, RGB5_A1, RGB565
// You can change this setting at any time.
[CCTexture2D setDefaultAlphaPixelFormat:kCCTexture2DPixelFormat_RGBA8888];
// Assume that PVR images have premultiplied alpha
[CCTexture2D PVRImagesHavePremultipliedAlpha:YES];
[self.view insertSubview:glView atIndex:0];
[[CCDirector sharedDirector] startAnimation];
}
The gesture recognizers are added to the glView and handled by the cocos2D game layer:
UIPanGestureRecognizer *panGestureRecognizer = [[[UIPanGestureRecognizer alloc] initWithTarget:layer action:#selector(handlePan:)] autorelease];
[[CCDirector sharedDirector].view addGestureRecognizer:panGestureRecognizer];
UITapGestureRecognizer *tapGestureRecognizer = [[[UITapGestureRecognizer alloc] initWithTarget:layer action:#selector(handleTap:)] autorelease];
[[CCDirector sharedDirector].view addGestureRecognizer:tapGestureRecognizer];
UIPinchGestureRecognizer *pinchGestureRecognizer = [[[UIPinchGestureRecognizer alloc] initWithTarget:layer action:#selector(handlePinch:)] autorelease];
[[CCDirector sharedDirector].view addGestureRecognizer:pinchGestureRecognizer];
This is driving me crazy; any help would be much appreciated.
I was able to solve this with the following steps:
Create the UIWindow with [UIScreen mainscreen].bounds as its frame, which will always be portrait. I was previously changing the window bounds depending on orientation which is incorrect.
Use the current status bar orientation to determine portrait/landscape and set the lowest level UIView's frame accordingly. (ie 1024x768 for landscape and 768x1024 for portrait)
Set the glView's frame to its parent UIView's bounds, NOT the window's bounds