I have a Universal app (iPhone/iPad) testing on IOS4.3. It has an iAd which I want to position at the bottom of the screen in both the orientations..
Below is the code;
- (void) viewWillAppear:(BOOL)animated {
adView_.requiredContentSizeIdentifiers = [NSSet setWithObjects: ADBannerContentSizeIdentifierPortrait, ADBannerContentSizeIdentifierLandscape, nil];
adView_.currentContentSizeIdentifier = ADBannerContentSizeIdentifierPortrait;
CGRect adFrame = adView_.frame;
adFrame.origin.y = self.view.frame.size.height-adView_.frame.size.height;
adView_.frame = adFrame;
adView_.delegate = self;
[webView addSubview:adView_];
[self.view bringSubviewToFront:adView_];
self.bannerIsVisible=NO;
[super viewWillAppear: animated];
}
Now for orienation handling, I have;
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
if (UIInterfaceOrientationIsLandscape(toInterfaceOrientation))
self.adView.currentContentSizeIdentifier = ADBannerContentSizeIdentifierLandscape;
else
self.adView.currentContentSizeIdentifier = ADBannerContentSizeIdentifierPortrait;
CGRect adFrame = adView_.frame;
adFrame.origin.y = self.view.frame.size.height-adView_.frame.size.height;
adView_.frame = adFrame;
[webView addSubview:adView_];
[self.view bringSubviewToFront:adView_];
self.bannerIsVisible=NO;
}
My issue is on app load (portrait), I am able to see the iAd clearly positioned at screen bottom.
But as soon as I change orientation to landscape, I cannot see the iAd. I see the message;
ADBannerView: WARNING A banner view (0x62534a0) has an ad but may be
obscured. This message is only printed once per banner view.
I guess I am doing something wrong inside willRotateToInterfaceOrientation
Please help me fix the issue.
Thank you.
Try moving your code to didRotateFromInterfaceOrientation. The new geometry is not set yet in willRotateToInterfaceOrientation.
Related
I've been struggling to figure out how Spotify creates the UI for when the app goes into offline mode. They make it seem like the StatusBar has resized, but in reality they're just putting a view below, and resizing all controllers throughout the app. I've tried subclassing UINavigationController, subclassing UIWindow, resizing the window, but nothing seems to work for every case.
The interesting thing about the Spotify app, is that their solution seems to still work when iOS' own UIViewController subclasses are presented modally (as seen in the image below, showing apple's MFMailComposeViewController - you can tell it's not a custom controller because of the UIBarButtonItems).
If anyone has any insight into how this is possible, that would be awesome.
it's a very dangerous thing to do. I've done in the past and I had nightmares. Below the code that works in iOS4 and supports orientation changes.
- (void) _adjustViewControllerforTicker {
TickerView* vv = [ApplicationContext getTickerView];
if ([PreferenceDataModel isFxTickerOn]&& self.navigationController.view.frame.origin.y==0) {
CGRect tableRect = self.tableView.frame;
self.tableView.frame = CGRectMake(tableRect.origin.x,tableRect.origin.y, tableRect.size.width, tableRect.size.height -20);
UINavigationController *nav = self.navigationController;
CGRect gframe = CGRectOffset(self.navigationController.view.frame, 0, 20);
self.navigationController.view.frame = gframe;
if (!vv) {
vv = [[TickerView alloc] initWithFrame:CGRectMake(0, 0, 480, 20)];
[nav.view addSubview:vv];
[vv release];
self.tableView.contentInset=UIEdgeInsetsMake(0,0,20.0,0.0);
[ApplicationContext setTickerView:vv];
}
if (![PreferenceDataModel isTickerOn]) {
self.tableView.contentInset= UIEdgeInsetsZero;
if (vv){
[vv removeFromSuperview];
vv=nil;
[ApplicationContext setTickerView:nil];
}
}
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
[self _adjustViewControllerforTicker];
}
- (void) viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self _adjustViewControllerforTicker];
TickerView* vv = [ApplicationContext getTickerView];
if ([vv count]) {
[vv startAnimation];
}
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self _adjustViewControllerforTicker];
}
And this is how it looks:
this is NOT a how do I force orientation of my app question as it might look like.
My problem is probably very simple, but it is hard to describe it so here goes.
I am trying to implement iAd to my iphone game. This is not a problem, it was a 10 minute fix, just follow tutorials on the web. However, my game was programmed by a contractor since I can't program very well and he made the game translated to landscape orientation instead of oriented to landscape. This has leads to some problems for me when trying to rotate the ads correctly.
Bottom line is that CGRect which is what iAd uses does simply not have the transform function so no matter what I do the ads are standing on their side. This is quite natural since the app doesn't know that the game is meant to be played in landscape.
After a full day of research it seems that I need to put my iAd CGRect in a different view and rotate that view using the CGAffineTransformMakeRotation. My really big problem is that I am not good enough at Objective-C to actually do that.
So can you help me how I should be able to apply transform to my ad?
Code below compiles and shows the ad but standing on its side (when holding the game in landscape)
//iAD starts
// lower right:-136, 295, 320, 32 lower left:-136, 135, 320, 32 upper right:136, 295, 320, 32
// *Controller becomes a UIViewController
UIViewController *controller = [[UIViewController alloc] init];
controller.view.frame = CGRectMake(100, 100, 320, 32);
//controller.view.transform = CGAffineTransformMakeRotation(M_PI / 2.0); // turn 180 degrees
NSLog(#"*controller");
//adView becomes a CGRectZero called adView
adView = [[ADBannerView alloc] initWithFrame:CGRectZero];
//adView.frame = CGRectOffset(adView.frame, 0, 0);
adView.requiredContentSizeIdentifiers = [NSSet setWithObjects:ADBannerContentSizeIdentifierLandscape,ADBannerContentSizeIdentifierPortrait,nil];
adView.currentContentSizeIdentifier = ADBannerContentSizeIdentifierLandscape;
[self.view addSubview:adView];
adView.delegate=self;
//self.bannerIsVisible=NO;
// iAD ends
Best regards
Marcus
This should rotate as you are asking.
This code has worked for me in my iAd apps: Directly from Apple Source Code
.h
#import <UIKit/UIKit.h>
#import <iAd/iAd.h>
#interface TextViewController : UIViewController <ADBannerViewDelegate>
{
UIView *contentView;
ADBannerView *banner;
}
#property(nonatomic, retain) IBOutlet UIView *contentView;
#property(nonatomic, retain) IBOutlet ADBannerView *banner;
#end
.m
#import ".h"
#interface TextViewController()
// Layout the Ad Banner and Content View to match the current orientation.
// The ADBannerView always animates its changes, so generally you should
// pass YES for animated, but it makes sense to pass NO in certain circumstances
// such as inside of -viewDidLoad.
-(void)layoutForCurrentOrientation:(BOOL)animated;
// A simple method that creates an ADBannerView
// Useful if you need to create the banner view in code
// such as when designing a universal binary for iPad
-(void)createADBannerView;
#end
#implementation TextViewController
#synthesize contentView, banner;
-(void)viewDidLoad{
[super viewDidLoad];
// If the banner wasn't included in the nib, create one.
if(banner == nil)
{
[self createADBannerView];
}
[self layoutForCurrentOrientation:NO];
}
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
[self layoutForCurrentOrientation:NO];
}
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation{
return YES;
}
-(void)willAnimateRotationToInterfaceOrientation: (UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration{
[self layoutForCurrentOrientation:YES];
}
-(void)createADBannerView{
// --- WARNING ---
// If you are planning on creating banner views at runtime in order to support iOS targets that don't support the iAd framework
// then you will need to modify this method to do runtime checks for the symbols provided by the iAd framework
// and you will need to weaklink iAd.framework in your project's target settings.
// See the iPad Programming Guide, Creating a Universal Application for more information.
// http://developer.apple.com/iphone/library/documentation/general/conceptual/iPadProgrammingGuide/Introduction/Introduction.html
// --- WARNING ---
// Depending on our orientation when this method is called, we set our initial content size.
// If you only support portrait or landscape orientations, then you can remove this check and
// select either ADBannerContentSizeIdentifierPortrait (if portrait only) or ADBannerContentSizeIdentifierLandscape (if landscape only).
NSString *contentSize;
if (&ADBannerContentSizeIdentifierPortrait != nil)
{
contentSize = UIInterfaceOrientationIsPortrait(self.interfaceOrientation) ? ADBannerContentSizeIdentifierPortrait : ADBannerContentSizeIdentifierLandscape;
}
else
{
// user the older sizes
contentSize = UIInterfaceOrientationIsPortrait(self.interfaceOrientation) ? ADBannerContentSizeIdentifier320x50 : ADBannerContentSizeIdentifier480x32;
}
// Calculate the intial location for the banner.
// We want this banner to be at the bottom of the view controller, but placed
// offscreen to ensure that the user won't see the banner until its ready.
// We'll be informed when we have an ad to show because -bannerViewDidLoadAd: will be called.
CGRect frame;
frame.size = [ADBannerView sizeFromBannerContentSizeIdentifier:contentSize];
frame.origin = CGPointMake(0.0f, CGRectGetMaxY(self.view.bounds));
// Now to create and configure the banner view
ADBannerView *bannerView = [[ADBannerView alloc] initWithFrame:frame];
// Set the delegate to self, so that we are notified of ad responses.
bannerView.delegate = self;
// Set the autoresizing mask so that the banner is pinned to the bottom
bannerView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleTopMargin;
// Since we support all orientations in this view controller, support portrait and landscape content sizes.
// If you only supported landscape or portrait, you could remove the other from this set.
bannerView.requiredContentSizeIdentifiers = (&ADBannerContentSizeIdentifierPortrait != nil) ?
[NSSet setWithObjects:ADBannerContentSizeIdentifierPortrait, ADBannerContentSizeIdentifierLandscape, nil] :
[NSSet setWithObjects:ADBannerContentSizeIdentifier320x50, ADBannerContentSizeIdentifier480x32, nil];
// At this point the ad banner is now be visible and looking for an ad.
[self.view addSubview:bannerView];
self.banner = bannerView;
[bannerView release];
}
-(void)layoutForCurrentOrientation:(BOOL)animated{
CGFloat animationDuration = animated ? 0.2f : 0.0f;
// by default content consumes the entire view area
CGRect contentFrame = self.view.bounds;
// the banner still needs to be adjusted further, but this is a reasonable starting point
// the y value will need to be adjusted by the banner height to get the final position
CGPoint bannerOrigin = CGPointMake(CGRectGetMinX(contentFrame),CGRectGetMaxY(contentFrame));
CGFloat bannerHeight = 0.0f;
// First, setup the banner's content size and adjustment based on the current orientation
if(UIInterfaceOrientationIsLandscape(self.interfaceOrientation))
banner.currentContentSizeIdentifier = (&ADBannerContentSizeIdentifierLandscape != nil) ? ADBannerContentSizeIdentifierLandscape : ADBannerContentSizeIdentifier480x32;
else
banner.currentContentSizeIdentifier = (&ADBannerContentSizeIdentifierPortrait != nil) ? ADBannerContentSizeIdentifierPortrait : ADBannerContentSizeIdentifier320x50;
bannerHeight = banner.bounds.size.height;
// Depending on if the banner has been loaded, we adjust the content frame and banner location
// to accomodate the ad being on or off screen.
// This layout is for an ad at the bottom of the view.
if(banner.bannerLoaded)
{
contentFrame.size.height -= bannerHeight;
bannerOrigin.y -= bannerHeight;
}
else
{
bannerOrigin.y += bannerHeight;
}
// And finally animate the changes, running layout for the content view if required.
[UIView animateWithDuration:animationDuration
animations:^{
contentView.frame = contentFrame;
[contentView layoutIfNeeded];
banner.frame = CGRectMake(bannerOrigin.x, bannerOrigin.y, banner.frame.size.width, banner.frame.size.height);
}];
}
-(void)viewDidUnload{
self.contentView = nil;
banner.delegate = nil;
self.banner = nil;
}
-(void)dealloc{
[contentView release]; contentView = nil;
banner.delegate = nil;
[banner release]; banner = nil;
[super dealloc];
}
#pragma mark ADBannerViewDelegate methods
-(void)bannerViewDidLoadAd:(ADBannerView *)banner{
[self layoutForCurrentOrientation:YES];
}
-(void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error{
[self layoutForCurrentOrientation:YES];
}
-(BOOL)bannerViewActionShouldBegin:(ADBannerView *)banner willLeaveApplication:(BOOL)willLeave{
return YES;
}
-(void)bannerViewActionDidFinish:(ADBannerView *)banner{
}
#end
If the game is rotated, why don't you stop the rotation of the game?
I managed to do what I wanted by using a different ad SDK (mobfox) the rotation I wanted to do looks like this:
// MOBFOX Starts
// create the banner view just outside of the visible area
MobFoxBannerView *bannerView = [[MobFoxBannerView alloc] initWithFrame:
CGRectMake(-800, self.view.bounds.size.height - 240, 320, 50)];
bannerView.delegate = self; // triggers ad loading
//bannerView.backgroundColor = [UIColor darkGrayColor]; // fill horizontally
bannerView.transform = CGAffineTransformMakeRotation(M_PI / 2.0);
//bannerView.refreshAnimation = UIViewAnimationTransitionCurlDown;
[self.view addSubview:bannerView];
NSLog(#"MobFox: Ad initated and placed offscreen");
//
The transform = CGAffineTransformMakeRotation was not accepted by the iAd stuff and since I am too weak on objective-c to force it to my will. This is what I did.
Thanks for offering to help!
I have an iAd which displays at the top of a fullscreen subview of the main view. The iAd works normally in portrait mode, and I have handled rotation of the iAd banner view into landscape mode. The issue occurs when the iAd is tapped by the user in landscape mode. The test advertisement displays in portrait, sideways on the phone, and when the user taps the x to dismiss the iAd, the banner view and its parent view are pushed offscreen. The iAd behaves normally in portrait mode (i.e. tapping it and closing it results in the view containing the banner to be displayed normally).
Things I have tried:
- (void)bannerViewActionDidFinish:(ADBannerView *)banner{
NSLog(#"Ad was closed, show the adView again");
if(UIInterfaceOrientationIsLandscape(currentInterfaceOrientation)){
[self animateRotationToLandscape:0.3f];
}
else{
[self animateRotationToPortrait:0.3f];
}
}
-(void)animateRotationToPortrait:(NSTimeInterval)duration{
self.adView.currentContentSizeIdentifier =
ADBannerContentSizeIdentifierPortrait;
BOOL iPad = NO;
#ifdef UI_USER_INTERFACE_IDIOM
iPad = (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad);
#endif
if (iPad) {
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:duration];
proUpgradeDescription.frame = CGRectMake(82,313,604,110);
proUpgradePrice.frame = CGRectMake(313,576,142,28);
closeButton.frame = CGRectMake(348,834,72,37);
purchaseButton.frame = CGRectMake(313,431,142,142);
[UIView commitAnimations];
}
else{
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:duration];
proUpgradeDescription.frame = CGRectMake(20,80,280,70);
proUpgradePrice.frame = CGRectMake(88,322,142,28);
closeButton.frame = CGRectMake(123,403,72,37);
purchaseButton.frame = CGRectMake(88,172,142,142);
[UIView commitAnimations];
}
}
Which calls code that I use to animate rotation of the display for portrait and landscape mode. This code has no effect.
If anyone has any ideas as to why the test advertisements don't rotate correctly and why they push the parent view controller off the screen I would greatly appreciate it.
I don't know if this addresses all of your problems, but according to the answer on this question, the test ads are only in portrait, and real ads will show up in both orientations.
I know the question is a little old so I'm posting here just in case someone runs into the same problem (I did).
ADBannerView messes with the frame and transform properties of the parent view so all you have to do is to reset them to their original values after it has finished (in bannerViewActionDidFinish:).
I still don't understand why it doesn't put back everything the way it was after it has finished. We shouldn't have to do this.
This drove me nuts too. Delivering only landscape full page ads to the iPad and portrait to the iPhone and not saying so is asking for trouble. I gave up using the iAdSuite code, which caused the Landscape iPad ad to leave the screen in Landscape even when the device was in portrait!
This is my code for banner ads. It is all in the first view controller loaded. It aims to put the banner at the bottom of the screen.
In the header file:
#import "iAd/ADBannerView.h"
#property (strong, nonatomic) ADBannerView* adView;
#interface myViewController : UIViewController <ADBannerViewDelegate,
in viewDidLoad
CGRect contentFrame = self.view.bounds;
CGRect bannerFrame = CGRectZero;
bannerFrame.size = [adView sizeThatFits:contentFrame.size];
bannerFrame.origin.y = contentFrame.size.height-bannerFrame.size.height;
adView = [[ADBannerView alloc] initWithFrame:bannerFrame];
[adView setDelegate:self];
[self.view addSubview:adView];
Then
-(void)viewWillLayoutSubviews {
CGRect contentFrame = self.view.bounds;
CGRect bannerFrame=CGRectZero;
bannerFrame.size = [adView sizeThatFits:contentFrame.size];
if (adView.bannerLoaded) {bannerFrame.origin.y = contentFrame.size.height-bannerFrame.size.height;}
else {bannerFrame.origin.y = contentFrame.size.height;}
[adView setFrame:bannerFrame];}
Then to handle the callbacks from iAd we need to tell the view to redo its layout if something changes:
- (void)bannerViewDidLoadAd:(ADBannerView *)banner{
[UIView animateWithDuration:0.25 animations:^{
[self.view setNeedsLayout];
[self.view layoutIfNeeded];
}];}
- (void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error{
[UIView animateWithDuration:0.25 animations:^{
[self.view setNeedsLayout];
[self.view layoutIfNeeded];
}];}
This seems to handle the orientation correctly on both iPad and iPhone except for the test full page ads. However, the screen assume correct orientation after the test ad is dismissed so I am hoping it is all OK.
In an iOS 4.2 application, I've programmatically created a window, view controller, UIView and two subviews: an EAGLView and an ADBannerView. My code is a combination of a standard EAGLView and Apple's BasicAdBanner code.
I'm able to see iAd banners, but am not able to "click" on them - on device or in simulator. The view controller implements ADBannerDelegate, and receives bannerViewDidLoadAd etc messages, but does not ever receive a bannerViewActionShouldBegin message.
The behaviour is not changed by replacing the EAGL view with a UITextView or only having the ADBannerView, so I'm assuming that my problem lies with the programmatic creation of the window or view controller. Any help would be appreciated.
In addition, my views don't rotate/resize automatically like the ad banner sample does, but that's a less pressing issue.
Code Follows-
AppDelegate:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Create the window programatically:
window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
// let's enable multitouch and user interaction
window.userInteractionEnabled=YES;
window.multipleTouchEnabled=YES;
window.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
window.autoresizesSubviews = YES;
controller = [GLViewController alloc];
window.rootViewController = controller;
[window addSubview:controller.view];
glView = [controller.glView retain];
[window makeKeyAndVisible];
return YES;
}
ViewController:
- (void)loadView
{
self.view = [[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds];
}
-(void)viewDidLoad
{
[super viewDidLoad];
// I'd like to get device orientation notifications.
//[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
//[[NSNotificationCenter defaultCenter] addObserver:self
// selector:#selector(didRotate:) name:UIDeviceOrientationDidChangeNotification object:nil];
// the GL VIEW I want.
glView = [[EAGLView alloc] initWithFrame:[UIScreen mainScreen].bounds];
glView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleBottomMargin;
glView.userInteractionEnabled=NO;
[self.view addSubview:glView];
// testing with a textview
//content = [[UITextView alloc] initWithFrame:[UIScreen mainScreen].bounds];
//content.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleBottomMargin;
//content.userInteractionEnabled=NO;
//[self.view addSubview:content];
if (self.banner==NULL)
[self createADBannerView];
[self layoutForCurrentOrientation:NO];
}
-(void)createADBannerView
{
// --- WARNING ---
// If you are planning on creating banner views at runtime in order to support iOS targets that don't support the iAd framework
// then you will need to modify this method to do runtime checks for the symbols provided by the iAd framework
// and you will need to weaklink iAd.framework in your project's target settings.
// See the iPad Programming Guide, Creating a Universal Application for more information.
// http://developer.apple.com/iphone/library/documentation/general/conceptual/iPadProgrammingGuide/Introduction/Introduction.html
// --- WARNING ---
// Depending on our orientation when this method is called, we set our initial content size.
// If you only support portrait or landscape orientations, then you can remove this check and
// select either ADBannerContentSizeIdentifierPortrait (if portrait only) or ADBannerContentSizeIdentifierLandscape (if landscape only).
NSString *contentSize;
if (&ADBannerContentSizeIdentifierPortrait != nil)
{
contentSize = UIInterfaceOrientationIsPortrait(self.interfaceOrientation)
? ADBannerContentSizeIdentifierPortrait : ADBannerContentSizeIdentifierLandscape;
}
else
{
// user the older sizes
contentSize = UIInterfaceOrientationIsPortrait(self.interfaceOrientation)
? ADBannerContentSizeIdentifier320x50 : ADBannerContentSizeIdentifier480x32;
}
// Calculate the intial location for the banner.
// We want this banner to be at the bottom of the view controller, but placed
// offscreen to ensure that the user won't see the banner until its ready.
// We'll be informed when we have an ad to show because -bannerViewDidLoadAd: will be called.
CGRect frame;
frame.size = [ADBannerView sizeFromBannerContentSizeIdentifier:contentSize];
frame.origin = CGPointMake(0.0f, 0.0f);//CGRectGetMaxY(self.view.bounds)); // this can't be called until the view exists!
// Now to create and configure the banner view
ADBannerView *bannerView = [[ADBannerView alloc] initWithFrame:frame];
// Set the delegate to self, so that we are notified of ad responses.
bannerView.delegate = self;
bannerView.hidden = YES;
// Set the autoresizing mask so that the banner is pinned to the bottom
bannerView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleTopMargin;
// Since we support all orientations in this view controller, support portrait and landscape content sizes.
// If you only supported landscape or portrait, you could remove the other from this set.
bannerView.requiredContentSizeIdentifiers = [NSSet setWithObjects:ADBannerContentSizeIdentifierPortrait, ADBannerContentSizeIdentifierLandscape, nil];
//support for 4.0 and 4.1: //(&ADBannerContentSizeIdentifierPortrait != nil) ?[NSSet setWithObjects:ADBannerContentSizeIdentifierPortrait, ADBannerContentSizeIdentifierLandscape, nil]:[NSSet setWithObjects:ADBannerContentSizeIdentifier320x50, ADBannerContentSizeIdentifier480x32, nil];
// At this point the ad banner is now be visible and looking for an ad.
self.banner = bannerView;
[self.view addSubview:bannerView];
[bannerView release];
}
-(void)layoutForCurrentOrientation:(BOOL)animated
{
//CGFloat animationDuration = animated ? 0.2f : 0.0f;
// by default content consumes the entire view area
CGRect contentFrame = self.view.bounds;
// the banner still needs to be adjusted further, but this is a reasonable starting point
// the y value will need to be adjusted by the banner height to get the final position
CGPoint bannerOrigin = CGPointMake(CGRectGetMinX(contentFrame), CGRectGetMaxY(contentFrame));
CGFloat bannerHeight = 0.0f;
// First, setup the banner's content size and adjustment based on the current orientation
if(UIInterfaceOrientationIsLandscape(self.interfaceOrientation))
// if(UIDeviceOrientationIsLandscape([[UIDevice currentDevice] orientation]))
banner.currentContentSizeIdentifier = ADBannerContentSizeIdentifierLandscape;//(&ADBannerContentSizeIdentifierLandscape != nil) ? ADBannerContentSizeIdentifierLandscape : ADBannerContentSizeIdentifier480x32;
else
banner.currentContentSizeIdentifier = ADBannerContentSizeIdentifierPortrait;//(&ADBannerContentSizeIdentifierPortrait != nil) ? ADBannerContentSizeIdentifierPortrait : ADBannerContentSizeIdentifier320x50;
bannerHeight = banner.bounds.size.height;
// Depending on if the banner has been loaded, we adjust the content frame and banner location
// to accomodate the ad being on or off screen.
// This layout is for an ad at the bottom of the view.
if(banner.bannerLoaded)
{
// HMM this is going to be a problem for a GLView..
banner.hidden = NO;
contentFrame.size.height -= bannerHeight;
bannerOrigin.y -= bannerHeight;
NSLog(#"Banner will be %f x %f, content resized to %f x %f\n", banner.frame.size.width,bannerHeight,contentFrame.size.width,contentFrame.size.height);
}
else
{
banner.hidden = YES;
//bannerOrigin.y += bannerHeight;
NSLog(#"Banner will be offscreen, content resized to %f x %f\n", contentFrame.size.width,contentFrame.size.height);
}
//EDIT: contrary to my OP, this UIViewAnimateWithDuration code was not commented out!
// And finally animate the changes, running layout for the content view if required.
[UIView animateWithDuration:animationDuration
animations:^{
glView.frame = contentFrame;
[glView layoutIfNeeded];
banner.frame = CGRectMake(bannerOrigin.x, bannerOrigin.y, banner.frame.size.width, banner.frame.size.height);
}];
}
ADBannerViewDelegate:
-(void)bannerViewDidLoadAd:(ADBannerView *)banner
{
[self layoutForCurrentOrientation:YES];
}
-(void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error
{
NSLog(#"Failed to receive and ad: %s %s %s\n",error.localizedFailureReason.UTF8String, error.localizedDescription.UTF8String, error.localizedRecoverySuggestion.UTF8String);
[self layoutForCurrentOrientation:YES];
}
-(BOOL)bannerViewActionShouldBegin:(ADBannerView *)banner willLeaveApplication:(BOOL)willLeave
{
// this indicates that the banner has been clicked.. confirm?
NSLog(#"banner clicked: will %s application\n",willLeave?"leave":"cover");
return YES;
}
Just to reiterate what forksandhope said,
Placing the ADView in a UIView, then modifying the frame size of both causes the ADView to become un-clickable.
To get around this, create a super UIView and add your UIView and ADView to this view.
For example:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
// initialize the content UIView and/or UIViewController
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
// copy the content view to a class data member
_contentView = self.view;
// create the super UIView
self.view = [[UIView alloc] initWithFrame:_contentView.frame];
// add the content view to the super view
[self.view addSubview:_contentView];
if (self) {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(willBeginBannerViewActionNotification:) name:BannerViewActionWillBegin object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(didFinishBannerViewActionNotification:) name:BannerViewActionDidFinish object:nil];
}
return self;
}
Then when an ad is loaded, add the ADView to the super view:
- (void)showBannerView:(ADBannerView *)bannerView animated:(BOOL)animated
{
// ...
// add the AdView to the super view
[self.view addSubview:_adBanner.adBannerView];
// ...
}
Then layout your view as desired
- (void)layoutAnimated:(BOOL)animated
{
// ...
[UIView animateWithDuration:animated ? 0.4 : 0.0 animations:^{
_adBanner.adBannerView.frame = _bannerFrame;
[self.view layoutIfNeeded];
// update the content view AND NOT the super view
_contentView.frame = _contentFrame;
}];
// ...
}
Clarification:
It seems that problem is related to the code attempting to set or animate the content frame changes at the end of -layoutForCorrentOrientation(BOOL). if I only set the banner frame's location, I'm able to click the banner, but if I also attempt to set the glView's frame and recreate the surface, the banner does not respond to input.
//EDIT: contrary to my OP, this UIViewAnimateWithDuration code was not commented out!
// And finally animate the changes, running layout for the content view if required.
//[UIView animateWithDuration:animationDuration
// animations:^{
// glView.frame = contentFrame;
// [glView layoutIfNeeded];
banner.frame = CGRectMake(bannerOrigin.x, bannerOrigin.y, banner.frame.size.width, banner.frame.size.height);
// }];
APENDED:
In the end, the problem was that I have a top level UIView (controller.view) which has the glView and the banner as sub-views. Turns out I needed to call
[self.view setNeedsLayout]
to get this top level view to update its bounds so that it allowed button presses down to the banner! (credit goes to Ephraim's answer to a post on UIButtons not responding after rotations
I got a problem to integrate iAd in my iPhone apps -- the banner ad is fine when it expends (see http://www.clingmarks.com/iAd1.png and http://www.clingmarks.com/iAd2.png), however, when I close it, it left a white blank screen (see http://www.clingmarks.com/iAd3.png). I couldn't figure out why. Here is how I integrate the ad:
Because I need to support other ads for lower version of iPhone OSes, I add a container view at the top of the apps, whose view controller is AdViewController. When the view is loaded, I create a AdBannerView programmatically and add it as a subview to the AdViewController.view. Here is the code in the viewDidLoad method:
Class adClass = (NSClassFromString(#"ADBannerView"));
if (adClass != nil) {
iAdView = [[ADBannerView alloc] initWithFrame:CGRectZero];
iAdView.frame = CGRectOffset(iAdView.frame, 0, -50);
iAdView.requiredContentSizeIdentifiers = [NSSet setWithObject:ADBannerContentSizeIdentifier320x50];
iAdView.currentContentSizeIdentifier = ADBannerContentSizeIdentifier320x50;
iAdView.delegate = self;
iadViewIsVisible = NO;
[self.view addSubview:iAdView];
} else {
// init google adsense
}
Following are the delegate methods:
enter code here
- (void)bannerViewDidLoadAd:(ADBannerView *)banner {
if (!iadViewIsVisible) {
[UIView beginAnimations:#"animateAdBannerOn" context:NULL];
// banner is invisible now and moved out of the screen on 50 px
banner.frame = CGRectOffset(banner.frame, 0, 50);
[UIView commitAnimations];
iadViewIsVisible = YES;
}
}
- (void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error {
if (iadViewIsVisible) {
[UIView beginAnimations:#"animateAdBannerOff" context:NULL];
// banner is visible and we move it out of the screen, due to connection issue
banner.frame = CGRectOffset(banner.frame, 0, -50);
[UIView commitAnimations];
iadViewIsVisible = NO;
}
}
Eventually I figured it out myself. It turns out the ADBannerView's parent view must be a fullscreen view. I my case above, I added AdBannerView to my adView, which is a view with size 320x50. When I changed its parent view to a fullscreen view, everything works. I am not sure if this is a bug in iAd, but certainly something tricky.
When the banner finishes, it moves itself to the top of the screen even if that means having a negative y coordinate. I center the banner when it finishes. In my case there is a view controller for just the banner, so it is only full screen when the ad is clicked.
-(void) bannerViewActionDidFinish:(UIView *)inBanner {
CGRect frame = [inBanner frame];
frame.origin.x = frame.size.width * 0.5;
frame.origin.y = frame.size.height * 0.5;
[inBanner setCenter:frame.origin];
}
Hey David! I know what you mean, I'm also using an own AdvertisementViewController which calls different ad networks.
So iAd is not in a full screen view but inside a 320x50 view.
Simply do this:
-(void) bannerViewActionDidFinish:(ADBannerView *)inBanner {
[self.view setFrame:CGRectMake(0.0f, 0.0f, 320.0f, 50.0f)];
}
So the outer view container (self.view) is resized to its original size. iAd is resizing it to fullscreen for displaying the ad when an iAd is shown.