I have a view controller and separate nib files for portrait and landscape. On rotating, I load the respective nib. The methods
shouldAutorotateToInterfaceOrientation and willRotateToInterfaceOrientation
get called and the nib does change.
The problem:
the landscape nib does not appear as landscape, but portrait! The status bar is
correctly rotated and appears on the top:
(Sorry, couldn't paste the image, because my account is new. The screenshot is in
landscape, with a landscape status bar, but a landscape view shown as portrait.)
One would think the problem lies in not setting the orientation as Landscape in IB Simulated metrics for the view, but I've done that and the view appears as landscape in IB. (I don't think it would even be possible to create a rotated button like that if the view was portrait.) Besides these two nibs I have a mainwindow.xib, which contains the app delegate, window and view controller objects.
EDIT: I realized that the views are actually rotating, when they should "stay up". It's like there's an extra transformation. When I rotate the phone 90° right, the landscape xib is displayed rotated 90° right. When I rotate the phone another 90° right, the portrait xib is displayed upside down. The status bar is always correctly displayed at the top.
EDIT2: Using
self.view.transform = CGAffineTransformMakeRotation((M_PI * (90) / 180.0));
in willRotateToInterfaceOrientation I can rotate the view to landscape left (and to any orientation I want), so I can use that as a workaround. However, I have other projects, where the view rotates automatically and doesn't require the use of CGAffineTransformMakeRotation. It's like something is preventing the automatic rotation here.
Are you adding the view loaded from nib as subView? If Only the status bar is rotating it means your previous view is hung while releasing the view and adding the new view.Can you tell how are you adding the view loaded from xib to the SuperView.
Make sure you are releasing the previous view correctly while loading the other view,put NSLOG in dealloc of the views and check whether the view is getting released completely.
I had done something similar to this only instead of making an nib file separately I just added two subviews to the main nib as prtraitView and Landscape View
and switched them as follows
In viewDidAppear method
-(void)viewDidAppear:(BOOL)animated{
if(UIDeviceOrientationIsPortrait(self.interfaceOrientation))
{
self.portraitVIew.frame=self.view.bounds;
self.portraitVIew.frame=self.view.frame;
[self.view addSubview:self.portraitVIew];
}else{
self.landscapeView.frame=self.view.frame;
[self.view addSubview:self.landscapeView];
}
self.view.autoresizesSubviews = YES;
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(deviceOrientationDidChangeNotification:)
name:UIDeviceOrientationDidChangeNotification
object:nil];
}
and then Implemented deviceOrientationDidChangeNotification as follows
- (void)deviceOrientationDidChangeNotification:(NSNotification*)note
{
if ([[UIDevice currentDevice] userInterfaceIdiom]==UIUserInterfaceIdiomPad) {
}else{
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
if(UIDeviceOrientationIsLandscape(self.interfaceOrientation))
{
self.landscapeView.hidden=NO;
self.landscapeView.frame=self.view.frame;
[self.portraitVIew removeFromSuperview];
[self.view addSubview:self.landscapeView];
}else {
self.landscapeView.hidden=YES;
self.portraitVIew.frame=self.view.frame;
NSLog(#"Portrait");
[self.view addSubview:self.portraitVIew];
}
}
}
It worked very well for me..
Related
I have 2 screens: the first screen support all orientations, the 2nd screen just support landscape right orientation.
I want the first screen to save its orientation before pushing to the second screen and return to that orientation when it pops back from the second screen.
my code:
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[[UIDevice currentDevice] setValue:#(currentOrientaion) forKey:#"orientation"];
[UIViewController attemptRotationToDeviceOrientation];
}
it's work but sometime screen rotates many time to change orientation.
Someone help me: why is that?
You should call these lines in some other method like ViewDidLoad because
for a specific view controller, viewWillAppear method may call multiple times.
I have an iOS application and the main entry point into the storyboard is a Tabbar with with tabs. I want to support rotation but in landscape mode, each tab will look drastically different to the point I need to change the views out with others from the storyboard. At first though, I considered just switching out the entire tab bar controller when the user rotates, but I don't see how that might be accomplished. So I have two options that I can't seem to get anywhere with.
Switch each view with a segue somehow into it's landscape alternative and back. I've seen this done easily with modal views, but not with UITabbar before.
Switch out the entire tab bar somehow from the delegate so that I just have two completely separate section of my storyboard that are alike except one path is portrait and the other is landscape.
Does anyone have anything similar they are doing and could throw me a bone?
You can create a custom class for both view controllers, link them together with segoes, and then use didRotateFromInterfaceOrientation: to trigger the segues from code.
Create a class for your VC's. Add this code to the .m file:
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
if (fromInterfaceOrientation == UIInterfaceOrientationLandscapeLeft || fromInterfaceOrientation == UIInterfaceOrientationLandscapeRight) {
[self performSegueWithIdentifier:#"rotateToPortrait" sender:nil];
} else {
[self performSegueWithIdentifier:#"rotateToLandscape" sender:nil];
}
}
And in your storyboard, create segues between the two views. Make their identifiers "rotateToPortrait" and "rotateToLandscape", respectively. The code you added will switch the views whenever the device is rotated.
EDIT: I think I misunderstood the question. If you want to move views around, change their size, etc. when the screen is rotated, while keeping the same navigation/tab bar state, then you can do something like this in the didRotateFromInterfaceOrientation method:
if (fromInterfaceOrientation == UIInterfaceOrientationLandscapeLeft || fromInterfaceOrientation == UIInterfaceOrientationLandscapeRight) {
myView.frame.origin.x = aNumber;
myView.frame.size.width = anotherNumber;
// Changing the layout of the views here by resetting their origins and sizes.
// This code is called when rotated from portrait to landscape.
} else {
// Do the same thing as above, but this one handles rotation from landscape to portrait.
}
I've got a SplitView Controller for iPad, which should display a Calculator which I made in portrait mode, and a Graph calculator when rotated into landscape mode.
This is what my storyboard looks like currently, am I doing it wrong?
I'm still new to the whole SplitView Controller concept in iOS, so I ain't sure how this whole thing works.
Currently, only the highlighted view gets displayed in both landscape and portrait mode, but I only want to display it in landscape mode, and display the calculator in portrait mode, as well as remove the option to display the Master button from portrait mode, but display it in landscape mode i.e. don't display the Master Table in landscape mode, only when the button is pressed.
Apple's SplitView Controller doesn't allow hiding the master view in landscape mode, but you could use a custom class, like this one.
For the screen-rotation part, just do a modal segue when the orientation changes.
This will notify you when the orientation changes:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(changeOrientation:) name:UIDeviceOrientationDidChangeNotification object:nil];
Then for the function
- (void) changeOrientation : (UIDeviceOrientation) orientation {
if(!UIDeviceOrientationIsValidInterfaceOrientation(orientation))
return;
if(orientation == UIDeviceOrientationLandscapeLeft || orientation == UIDeviceOrientationLandscapeRight) { // Or UIDeviceOrientationPortrait
[self performSegueWithIdentifier:#"SEGUENAME" sender:self];
}
}
More about segues: HERE
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)];
}
What I tried so far is, in viewDidLoad, I called
self.bannerView.autoresizingMask=UIViewAutoresizingFlexibleWidth;
and
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)newInterfaceOrientation duration:(NSTimeInterval)duration {
if (newInterfaceOrientation == UIInterfaceOrientationLandscapeLeft || newInterfaceOrientation == UIInterfaceOrientationLandscapeRight) {
self.bannerView.frame=CGRectMake(0.0,
0.0,
480.0,
GAD_SIZE_320x50.height);
}
// Position the UI elements for portrait mode
else {
self.bannerView.frame=CGRectMake(0.0,
0.0,
GAD_SIZE_320x50.width,
GAD_SIZE_320x50.height);
}
}
Both of these didn't work for me.
Hmm, I don't think that AdMob's creatives can stretch to fit the size of the screen when in landscape. So despite the fact that you're stretching the frame of the view to fit, the ad itself I think will stay the same size.
This means you should still see an ad come in on orientation changes, it will just look like it's the same size (make sure to make another request for an ad in the willAnimateRotationToInterfaceOrientation: method to see this).
You don't need to do any moves, but you must set correct rootViewController for adMovView.
If you use view controller model please add line in each custom view controller
adMobView.rootViewController = viewController;
where viewController - root view controller of your app.
Do not code like this
adMobView.rootViewController = self;
in custom view!