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!
Related
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.
}
My iPad application opens modal view controller with 'Page' presentation style. As you know 'Page' presentation style doesn't cover status bar of presenting view controller to indicate page presentation.
From the modal view controller the app opens UIImagePickerController to make photo. UIImagePickerController has 'Full screen' presentation style. After dismissing image picker presenting modal view controller become 20px taller and overlaps status bar of the initial view controller.
I tried to replace UIImagePickerController with simple UINavigationController and it breaks my modal view controller too.
There are screen shots:
They only way to restore size of 'Page' view controller is changing height of viewController.view.superview.superview.superview.superview frame after returning to 'Page' view controller. But it's really weird.
Is there another way to fix 'Page' modal view controller presentation after dismissing nested modal view controller?
UPDATE:
I used such weird code to solve my problem:
#define STATUS_BAR_HEIGHT 20
#define IPAD_PORTRAIT_HEIGHT 1004
#define IPAD_LANDSCAPE_HEIGHT 748
UIView *superview = nil;
// In case of this view controller included in navigationController we have to use superview of navigation's controller view
if (self.navigationController)
superview = self.navigationController.view.superview;
else
superview = self.view.superview;
CGRect r = superview.frame;
// Sometimes we have to fix height + origin, sometimes only height (becase view has bottom magnifying)
// In landscape orientation we have to fix 'width' instead of 'height', because that view controller always works in 'portrait' mode
if (self.interfaceOrientation == UIInterfaceOrientationPortrait && r.size.height > IPAD_PORTRAIT_HEIGHT) {
r.origin.y = STATUS_BAR_HEIGHT;
r.size.height = IPAD_PORTRAIT_HEIGHT;
}
else if (self.interfaceOrientation == UIInterfaceOrientationMaskPortraitUpsideDown && r.size.height > IPAD_PORTRAIT_HEIGHT) {
r.size.height = IPAD_PORTRAIT_HEIGHT;
}
else if (self.interfaceOrientation == UIInterfaceOrientationLandscapeLeft && r.size.width > IPAD_LANDSCAPE_HEIGHT) {
r.size.width = IPAD_LANDSCAPE_HEIGHT;
r.origin.x = STATUS_BAR_HEIGHT;
}
else if (self.interfaceOrientation == UIInterfaceOrientationLandscapeRight && r.size.width > IPAD_LANDSCAPE_HEIGHT) {
r.size.width = IPAD_LANDSCAPE_HEIGHT;
}
superview.frame = r;
I don't believe that there is no more elegant solution. Any ideas how to improve it?
UPDATE2: I've just opened a bug. You can follow it there: rdar://15949644
UPDATE3: There is my sample project: link
There is no good solution, it's an Apple bug, and until it is fixed, you have to work around it. It has not been fixed in iOS 7.1. I worked on a solution to this and realized I was implementing the same solution as well. It's ugly, but it works.
A word on this design. My guess why Apple overlooked this problem is because presenting a view controller in fullscreen is not something Apple would do. This is not an excuse of course, and sometimes there is no other option but to present fullscreen (we had to open a camera view, which must be opened in fullscreen, for example). Perhaps you can change your design to accommodate Apple's bugs.
"Ensure that the ViewController that is presenting the modal view is in a NavigationController and this weirdness should stop. " My initial answer - wrong
Updated
This does indeed sound like a bug, although from a user experience point of view one you shouldn't really hit. It seems a little wrong to present a view controller that is in the 'Page' presentation style and then to present another over it in full screen mode.
IMO that's just bad design from the outset so the fact that it doesn't act as you'd expect probably is because whoever set it up didn't anticipate someone using it like that.
I would, pretty much as my initial answer stated albeit briefly, embed your modally presented view controller in a navigation controller and push the UIImagPickerViewController in to that or add it's view animated to yours as if it then appears to be presented like another page styled modal view. If that's you desired affect.
None of that sounds perfect, a more perfect solution would be to look at the flow of you app and perhaps reevaluate how things are presented.
I think it is a problem of iOS7 where layouts of Views has been slightly changed.
I had similar problem with a pop modal custom View where I noticed the same behavior.
I solved by adding this line in the viewDidLoad
self.edgesForExtendedLayout = UIRectEdgeNone;
Maybe it could be useful for some hint to your problem.
There is definitely a problem with UIImagePicker (or more broadly, UINavigationController) not obeying any status bar settings in the application.
This has been discussed and solved by reapply your status bar settings in the UINavigationController delegate (see UIImagePickerController breaks status bar appearance).
In your case, you might want to call self.edgesForExtendedLayout = UIRectEdgeNone; or try ressetting some status bar properties in the delegate callback
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated;
Looks like it's an iOS bug and for now it can be solved with such workaround (it's a method of 'Page' modal view controller)
#define STATUS_BAR_HEIGHT 20
#define IPAD_PORTRAIT_HEIGHT 1004
#define IPAD_LANDSCAPE_HEIGHT 748
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear: animated];
// In case of iOS7 we need this weird code, because after displaying full screen view controller from 'Page' modal view controller our 'Page' controller
// incorrectly shifts 20px up
//
// I haven't found best solution for now
// There is my question on SO: http://stackoverflow.com/questions/21146801/ipad-ios7-page-modal-view-controller-strange-behaviour-after-presenting-full
if (!isIOS6()) {
[self setNeedsStatusBarAppearanceUpdate];
UIView *superview = nil;
// In case of this view controller included in navigationController we have to use superview of navigation's controller view
if (self.navigationController)
superview = self.navigationController.view.superview;
else
superview = self.view.superview;
CGRect r = superview.frame;
// Sometimes we have to fix height + origin, sometimes only height (becase view has bottom magnifying)
// In landscape orientation we have to fix 'width' instead of 'height', because that view controller always works in 'portrait' mode
if (self.interfaceOrientation == UIInterfaceOrientationPortrait && r.size.height > IPAD_PORTRAIT_HEIGHT) {
r.origin.y = STATUS_BAR_HEIGHT;
r.size.height = IPAD_PORTRAIT_HEIGHT;
}
else if (self.interfaceOrientation == UIInterfaceOrientationMaskPortraitUpsideDown && r.size.height > IPAD_PORTRAIT_HEIGHT) {
r.size.height = IPAD_PORTRAIT_HEIGHT;
}
else if (self.interfaceOrientation == UIInterfaceOrientationLandscapeLeft && r.size.width > IPAD_LANDSCAPE_HEIGHT) {
r.size.width = IPAD_LANDSCAPE_HEIGHT;
r.origin.x = STATUS_BAR_HEIGHT;
}
else if (self.interfaceOrientation == UIInterfaceOrientationLandscapeRight && r.size.width > IPAD_LANDSCAPE_HEIGHT) {
r.size.width = IPAD_LANDSCAPE_HEIGHT;
}
superview.frame = r;
}
}
Background:
My app was configured in portrait view by default, but for one scene the screen should be in landscape view only.
Question:
How to set the orientation manually with codes, in other words, users need not to rotate the device to generate an event to make the screen rotated.
PS:
I need a method like "setRequestedOrientation" in Android or I need to know how to construct a screen rotation event to send to the system.
Have you on the desired view controller tried
- (BOOL)shouldAutorotate
{
return YES;
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscape;
}
Another thing you can do is to change the orientation on the desired view controller from "Inferred" to "Landscape" in the Attributes inspector in your storyboard.
UIViewController Class Reference
Key:
Use CGAffineTransform CGAffineTransformMakeRotation(CGFloat angle) from CoreGraphics, which could make your view rotated
Sample Codes:
(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.view.transform = CGAffineTransformMakeRotation(M_PI/2);
self.view.frame = CGRectMake(0, 0, 480, 320);
}
I have a view that has two tables. In the story board, I have two separate views, one horizontal and the other vertical. When I need to navigate to the view, the code detects the orientation and brings up the appropriate view (and does so on an orientation change.
I have the following code in my method:
-(void)viewDidAppear:(BOOL)animated{
UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
if(orientation == UIInterfaceOrientationLandscapeLeft || orientation == UIInterfaceOrientationLandscapeRight){
if(tableHeight2 > 324){
tableHeight2 =325;
}
table1.frame = CGRectMake(table1.frame.origin.x, table1.frame.origin.y, table1.frame.size.width, tableHeight1);
table2.frame = CGRectMake(table2.frame.origin.x, table1.frame.origin.y + 20 + tableHeight1, table2.frame.size.width, tableHeight2);
}else {
if(tableHeight2 > 500){
tableHeight2 = 500;
}
table1.frame = CGRectMake(table1.frame.origin.x, table1.frame.origin.y, table1.frame.size.width, tableHeight1);
table2.frame = CGRectMake(table2.frame.origin.x, table1.frame.origin.y + 50 + tableHeight1, table2.frame.size.width, tableHeight2);
}
}
This works wonderfully when I press a button to navigate to the view. It adds up all of the cell heights and makes the first table the appropriate height, then moves the second table 50 pixels below the first table. It also makes sure the second table doesn't extend beyond the visible screen area.
When the orientation changes, I the following code is executed:
-(void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)orientation duration:(NSTimeInterval)duration {
InitViewController *ini;
ini = [self.storyboard instantiateViewControllerWithIdentifier:#"Init"];
ini.location = MenuName;
[self presentViewController:ini animated:NO completion:nil];
}
This should do the same thing that pressing a barbuttonitem does: change to InitViewController while sending the StoryboardID to it in the ini.location variable. The code for the navigation buttons is pretty much identical to the code in willAnimateRotationToInterfaceOrientation. InitViewController then determines the orientation and sends the app to the correct storyboard UIView.
It does send it to the right view, I can tell based on the table widths. What it doesn't do is change the height of the first (top) table, table1. The first table retains the size it was given in the storyboard.
If there is area of code you think I need to post to get a better picture, let me know I'll be happy to add it. Any help, insight, or even just trial-and-error suggestions would be appreciated.
*Note: I have tried to change willAnimateRotationToInterfaceOrientation to ViewDidLayoutSubviews, to not effect.
Well, it seems a very small change fixed it. I noticed that the code on the navigation buttons had YES under "animate" for the view change, and the willAnimateRotationToInterfaceOrientation "animated:NO". I changed it to "YES" and that fixed it. Not sure why yet, perhaps it affects how the method displays the view or affects the load order, but there it is.
I want to create a UIVIew that will not rotate when I will call to shouldAutorotateToInterfaceOrientation , and other subviews will rotate.
and i want to keep the shouldAutorotateToInterfaceOrientation suppot, and not use notification.
thanks
Be sure to define exactly what you mean by having a view "not rotate" when the device is rotated. Rotation can mean several things, depending on which coordinate system to which you refer. A better way to think about it is simply, what do you want your view to look like for each device orientation.
Just to remind, shouldAutorotateTo... is sent to your view controller by the system. You don't invoke it yourself. It doesn't cause rotation. It lets the system ask your view controller what orientations it supports.
Your VC should answer YES for all orientations it supports. A supported orientation is one where the view changes layout in response to a device orientation change, so if any layout change occurs for a given orientation, then the answer to shouldAutorotateTo is probably YES.
Altering subview layout for a given interface orientation is mostly your responsibility. Views have an autoresizingMask which is a bit vector describing some options for sizing and positioning relative to their parent, and this is often adequate. The way to fully control layout on orientation change is by implementing willAnimateRotationToInterfaceOrientation.
For example, here's a fairly permissive shouldAutorotate, enabling all but one orientation...
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
And here's how you would control how subviews layout on rotation...
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
UIView *testView = [self.view viewWithTag:16];
if (UIInterfaceOrientationIsLandscape(toInterfaceOrientation)) {
// change frames here to make the ui appear according to your spec
// including however you define "not rotating" for each view
self.subviewA.frame = .....
self.subviewB.frame = .....
} else {
self.subviewA.frame = .....
self.subviewB.frame = .....
}
}
If you want one UIView not to Rotate with orientation, one of the easy solution is to add that view to Application top Window like this. Because window dont rotate with device orientations.
[[[[UIApplication sharedApplication]windows]objectAtIndex:0]addSubview:customView];