Add UIView in Landscape mode - ios

I need to add the ads functionality in my iOS App. And ads screen would appear after some time interval. My whole is in Landscape mode only. When I tried to add the view on current view then it shows the views in portrait mode not in landscape mode. I have set the view frame i.e. CGSizeMake(0,0, 568, 320)
time = [NSTimer scheduledTimerWithTimeInterval:2.0f
target:self
selector:#selector(showfirstad)
userInfo:nil
repeats:YES];
-(void)showfirstad {
[[[[UIApplication sharedApplication] windows] lastObject] addSubview:firstad];
}
It appears like this .

_window = [UIApplication sharedApplication].keyWindow;
if (!_window) _window = [[UIApplication sharedApplication].windows objectAtIndex:0];
UIInterfaceOrientation orientation = self.window.rootViewController.interfaceOrientation;
// Set appropriate view frame (it won't be autosized by addSubview:)
CGRect appFrame = [[UIScreen mainScreen] applicationFrame];
if (UIInterfaceOrientationIsLandscape(orientation))
{
// Need to flip the X-Y coordinates for landscape
self.view_login.frame = CGRectMake(appFrame.origin.y, appFrame.origin.x, appFrame.size.height, appFrame.size.width+20);
else
{
self.view_login.frame = appFrame;
}
[[[_window subviews] objectAtIndex:0] addSubview:self.view_login];

The reason your UIView gets displayed in portrait orientation while the rest of your app gets displayed in landscape is because you are adding the UIView as a subview of your window rather than adding it as a subview of a view controller's view. This places it outside of the view hierarchy that gets transformed automatically through autorotation.
The app's window object coordinates autorotation by finding its topmost subview that has a corresponding view controller. Upon device rotation, the window calls shouldAutorotateToInterfaceOrientation: on this view controller and transforms its view as appropriate. If you want your view to autorotate, it must be a part of this view's hierarchy.
So instead of [window addSubview:UIView];, do something like [self.view addSubview:UIView];

I had the same issues with rotation and autolayots when used addSubview:myView.
I managed to solve this problem by using standard container controllers or placing views directly to storyboard.
You can probably just add the view that will keep your ad into the screen in storyboard and then set hidden property to YES. Then you can change it to YES after some time.

Related

Objective C iOS UISegmentedControl changing position unexpectedly

I have a UISegmented control that I need to change the position of whenever the view goes into a landscape view. My code works, but for some very strange reason whenever I try to select the segmented control, it moves back to its portrait position which is off of the screen. This is not happening with buttons that I am using the same method to move them with.
Code:
// handle landscape view
-(void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
CGSize size = [UIScreen mainScreen].bounds.size;
UIApplication *app = [UIApplication sharedApplication];
UIInterfaceOrientation orientation = [app statusBarOrientation];
if (UIInterfaceOrientationIsLandscape(orientation)) size = CGSizeMake(size.height, size.width);
if (!app.statusBarHidden) size.height -= MIN(app.statusBarFrame.size.width, app.statusBarFrame.size.height);
if (UIInterfaceOrientationIsLandscape(orientation))
{
// CGRects of segmented controls
CGRect modeFrame = [self offAutoHeatCool].frame;
CGRect fanModeFrame = [self fanMode].frame;
modeFrame.origin.y = someRelativeInt;
fanModeFrame.origin.y = someRelativeInt;
modeFrame.origin.x = someRelativeInt;
fanModeFrame.origin.x = someRelativeInt;
[[self modeLabel] setFrame:modeLabelFrame];
[[self offAutoHeatCool] setFrame:modeFrame];
}
}
Edit:
Please keep in mind that I need to move certain UI elements from being above or beneath each other to being on the side of relative UI elements. I'm not certain if you can do this using auto layout, and I would prefer to do so programmatically anyways.
The proper way to deal with views moving around resizing (or orientation changing) parent views is to use auto layout. It will save you a lot of hassle once you begin using it. Take a look at the documentation here:
https://developer.apple.com/library/ios/documentation/userexperience/conceptual/AutolayoutPG/Introduction/Introduction.html
Hope this helps!
I figured it out. All I had to do was disable auto layout for that view. To do this I selected the view controller in the storyboard, selected the file inspector, and unchecked "Use Auto Layout" under "Interface Builder Options".

IOS 6 view controller incorrect width / bounds - landscape mode

My app utilizes both landscape mode and portrait mode and the user can switch between the two at will.
When a view controller is presented by a parent view controller that is in portrait orientation, the opened view controller will have the correct width & frame.
However, if the parent view controller is in landscape mode, then on IOS6 (it works correctly on IOS7), the child view controller will be too large and actually a little too short also when it is presented.
Note this is not because the values are reported incorrectly since [[UIScreen mainScreen] bounds] reports the same values regardless of the orientation the child controller is loaded in.
Any ideas on how to fix this / why this is happening? Any idea on how to force the IOS6 versions to behave like IOS7 is now behaving natively? Many thanks!!!
Edit::
Here's how the vc's are presented:
AppDelegate
Launch1 *launch1 =[[Launch1 alloc] init];
self.window.rootViewController = launcher;
[self.window makeKeyAndVisible];
Launch1 class
Search *search = [[Search alloc] init];
[self presentViewController:search animated:YES completion:nil];
Search class
//load list_container
views = [[Search_custom_views alloc] initWithControllerContext:self];
[self.view addSubview:views];
Search_custom_views UIView extension:
- (id)initWithControllerContext:(UIViewController*)contextstart {
//set size of the screen
CGRect screenRect = [[UIScreen mainScreen] bounds];
self = [super initWithFrame:screenRect];
if (self) {
....
So this was a tough one. I load all my views programmatically. They basically are UIView subclasses that correspond to each view controller. For some reason, when an IOS6 view controller is opened from a parent view controller in landscape mode, the child view controller's bounds are not immediately passed on the child vc's UIView subclasses (if you just use addSubview in the viewDidLoad method of the controller--it is not enough). IOS7 does not have this problem.
The fix for IOS6 for me was doing the following in the viewDidLoad method of the child view controller:
//add view subclass to view controller
[self.view addSubview:views];
//reset bounds & refresh layout for IOS6
if ([[[UIDevice currentDevice] systemVersion] floatValue] < 7) {
views.frame = self.view.bounds;
[views layoutIfNeeded];
}
iOS 7 likes it when you call [[UIScreen mainScreen] bounds] instead of [[UIScreen mainScreen] applicationFrame] because the applicationFrame property is not consistently calculated between different versions of iOS, while bounds is.
It should be backwards compatible, so you should be able to do something like this:
- (CGRect)filterBankFrameForOrientation:(UIInterfaceOrientation)orientation {
CGRect appFrame = [[UIScreen mainScreen] bounds];
if (UIInterfaceOrientationIsLandscape(orientation)) {//using bounds here instead of applicationFrame for iOS7 compatibility
//Handle landscape orientation
filterBankFrame = CGRectMake(0.0, k_filterBankOffsetFromTop, appFrame.size.height, k_filterBankHeight);
}
else {
//Handle portrait orientation
filterBankFrame = CGRectMake(0.0, k_filterBankOffsetFromTop, appFrame.size.width, k_filterBankHeight);
}
return filterBankFrame;
}
and simply flip the height and width values as needed (since bounds will always be in "portrait" orientation)
Using bounds should give you the consistency you need for identical behavior across iOS versions and device sizes.
Updating in response to OP's updated code
One approach I'd recommend you at least consider is wiring up these views in InterfaceBuilder and using AutoLayout to worry about the rotations for you. It has the added benefit of gracefully handling ALL of the different screen sizes available too, so that can be nice too.
Still, creating and managing it all in code is perfectly acceptable too, and may be the right call for your situation. If so, you'll want to override a few of the rotation handling methods of UIViewController. Probably most or all of these:
– shouldAutorotate
– supportedInterfaceOrientations
– preferredInterfaceOrientationForPresentation
– willRotateToInterfaceOrientation:duration:
- didRotateFromInterfaceOrientation
at a minimum the first one and the last two.
To avoid being tied to one orientation only at launch, it is a common design pattern (citation needed) to write a method like the one I posted above, and then utilize it from both viewDidLoad as well as from the willRotate / didRotate class methods.
When calling during viewDidLoad, you do something like this:
_filterBank.collectionView.frame = [self filterBankFrameForOrientation:[[UIApplication sharedApplication] statusBarOrientation]];
which uses the statusBarOrientation property to launch correctly in either landscape or portrait.
The willRotate / didRotate methods both give you a parameter you can pass to your frame generating method.
Your method gives you the right frame size, then it's all up to you to pass down this info and manipulate your view hierarchy accordingly. It's easier than it sounds...
(in your case, it looks like launcher would implement the methods, then coordinate the adjustments to launch1 and then down to search and finally to Search_custom_views)
(**last side note, you'll make more friends here by choosing SearchCustomViews instead of Search_custom_views)

transitionWithView animation for LandsCape view is weird?

For All ViewControllers in my application I used Landscape mode ie I have Changed the Orientation option to LandScape in the Inspector Pane for the UIView of the ViewController in xib. I used the animation mentioned here.
As I don't want to keep many View Controllers in memory, while showing next ViewController I use to load them as rootViewController of the application key window
[UIView transitionWithView:self.window
duration:0.8
options:UIViewAnimationOptionTransitionFlipFromTop//But rotating left to roght in portrait mode
animations:^{
self.window.rootViewController = currentView;
}
completion:nil];
My problem is that during the animation phase Instead of animating in the landscape mode, the View is animated in portrait mode after the animation ends the View comes to the LanscapeMode,

iOS Truncated Views while rotating, have to reset view.bounds

I've been adding support for rotation for an app recently and it has been a pain. One thing I'm finding that's fairly consistently annoying is that one of my views shifts up by about 50 pixels or so everytime I rotate between my landscape and portrait mode.
My landscape mode is not actually the same view controller; I push a viewcontroller when I rotate. However, when I rotate back, I have to reset the portrait's view.bounds or else my view ends up shifting upwards.
So in my rotation code, I have to do this:
-(void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
UIInterfaceOrientation toOrientation = self.interfaceOrientation;
if ( self.tabBarController.view.subviews.count >= 2 )
{
if(toOrientation == UIInterfaceOrientationPortrait)
{
self.tabBarController.tabBar.hidden = NO;
self.navigationController.navigationBar.hidden = NO;
CGFloat height = [[UIScreen mainScreen] bounds].size.height;
CGFloat width = [[UIScreen mainScreen] bounds].size.width;
self.view.bounds = CGRectMake(0, -55, width, height);
}
}
}
Surely this can't be right. In my app, there is a navbar and the standard status bar (batt life, reception, etc) occupying the top of my app. But...it seems like my view is slipping too upwards unless I set the y coordinate origin to be negative (which makes no sense!).
What's happening?
In my app, I hide the tabbar and navbar when I go to landscape mode. The statements to make the bars hidden are written into the portrait view's viewcontroller's code.
When I transition back from landscape mode to portrait mode, the landscape viewcontroller gets popped and I get the weird shifted views. Turns out this was caused by the order in which the tab/nav bar un-hiding statements.
My tab/nav bar un-hiding statements were in the portrait viewcontroller, so they were called too late. After moving the tab/nav un-hiding statements to the rotation code in the landscape viewcontroller (rather than the portrait's viewcontroller), my problem disappeared.

Force parentView to refresh view after navigation controller pops out a child view

I have secondViewController that can display content in both landscape and portrait view. The MainViewController (parent of secondViewController) can only display content in landscape mode.
When SecondView is in portrait mode and is pop out, the view the MainViewController (which is supposed to display content in landscape mode only) displays content in portrait. It does not refresh to landscape mode.
Is there a way to force MainViewController to refresh the content?
On the MainViewController's viewWillAppear method, I have added setNeedsDisplay and layoutSubviews, etc.
-(void) viewWillAppear:(BOOL)animated {
[self.view setNeedsDisplay];
[self.view layoutIfNeeded];
[self.view layoutSubviews];
}
but it is not reloading the view. I also tried the navigation controller's delegate method - willShowViewController but its not working.
I solved a similar problem by not letting he user "go back" to the other view unless the app was in the proper orientation (in this case Landscape). What you can do is provide your own "Back" button, and if the view is in Portrait, pop an alert that says please rotate to Landscape first (or better yet animate a small view in from the bottom or top of the screen). Or just hide or disable the back button in portrait (I hid the button).
Its a terrible UI choice to let the user go back, and see the view in landscape while the phone is in portrait mode in any case.
Looks like if you remove the view and add it back it works
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
if (UIDeviceOrientationIsPortrait(orientation)){
NSLog(#"force to landscape mode ");
UIWindow *window = [[UIApplication sharedApplication] keyWindow];
UIView *view = [window.subviews objectAtIndex:0];
[view removeFromSuperview];
[window addSubview:view];
}
You can also use CGAffineTransformMakeRotation but it the rotation does not work on the navigation controller
if (orientation == UIDeviceOrientationPortraitUpsideDown) {
[self.view setTransform:CGAffineTransformMakeRotation(M_PI/-2.0)];
//[self.navigationController.view setTransform:CGAffineTransformMakeRotation(M_PI/-2.0)];
} else if (orientation == UIDeviceOrientationPortrait) {
[self.view setTransform:CGAffineTransformMakeRotation(M_PI/2.0)];
//[self.navigationController.view setTransform:CGAffineTransformMakeRotation(M_PI/-2.0)];
}

Resources