无法在以编程方式创建的窗口中单击 iAd - 未调用bannerViewActionShouldBegin?

Posted

技术标签:

【中文标题】无法在以编程方式创建的窗口中单击 iAd - 未调用bannerViewActionShouldBegin?【英文标题】:iAd cannot be clicked in programmatically created window - bannerViewActionShouldBegin not called? 【发布时间】:2011-01-19 22:33:00 【问题描述】:

ios 4.2 应用程序中,我以编程方式创建了一个窗口、视图控制器、UIView 和两个子视图:一个 EAGLView 和一个 ADBannerView。我的代码是标准 EAGLView 和 Apple 的 BasicAdBanner 代码的组合。

我可以看到 iAd 横幅,但无法“点击”它们 - 在设备上或在模拟器中。视图控制器实现了 ADBannerDelegate,并接收 bannerViewDidLoadAd 等消息,但从未接收到 bannerViewActionShouldBegin 消息。

用 UITextView 替换 EAGL 视图或仅使用 ADBannerView 不会改变行为,因此我假设我的问题在于以编程方式创建窗口或视图控制器。任何帮助将不胜感激。

此外,我的视图不会像广告横幅示例那样自动旋转/调整大小,但这是一个不太紧迫的问题。

代码跟随-

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;

视图控制器:

- (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;

【问题讨论】:

我删除了我的答案,因为他们都错了。希望您应该得到更多的关注,而不会出现我的错误答案。 似乎问题与尝试在 -layoutForCorrentOrientation(BOOL) 末尾设置或动画内容框架更改的代码有关。如果我只设置横幅框架的位置,我可以单击横幅,但如果我还尝试设置 glView 的框架并重新创建表面,横幅不会响应输入。 这个问题已经解决了我的旋转问题:***.com/questions/1299239/… -- 我必须使用 glview==main 视图设置我的控制器,并使用主视图来旋转横幅和任何其他重叠的按钮。然后,在我的***视图上调用 setNeedsLayout 修复了我无响应的按钮问题。 【参考方案1】:

只是重申一下forksandhope所说的,

将 ADView 放在 UIView 中,然后修改两者的帧大小会导致 ADView 变得不可点击。

要解决这个问题,请创建一个超级 UIView 并将您的 UIView 和 ADView 添加到此视图。

例如:

- (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;

然后在加载广告时,将 ADView 添加到超级视图中:

- (void)showBannerView:(ADBannerView *)bannerView animated:(BOOL)animated

     // ...

        // add the AdView to the super view
        [self.view addSubview:_adBanner.adBannerView];

     // ...


然后根据需要布局您的视图

- (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;
    ];

    // ...


【讨论】:

优秀的解决方案!请在视图控制器中添加它。我知道它在问题中,但答案是独立的。谢谢!【参考方案2】:

澄清: 似乎问题与尝试在 -layoutForCorrentOrientation(BOOL) 末尾设置或动画内容框架更改的代码有关。如果我只设置横幅框架的位置,我可以单击横幅,但如果我还尝试设置 glView 的框架并重新创建表面,则横幅不会响应输入。

//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);
//                 ];

附加: 最后,问题是我有一个*** UIView (controller.view),它有 glView 和横幅作为子视图。原来我需要打电话

[self.view setNeedsLayout]

让这个***视图更新它的边界,以便它允许按钮按下到横幅! (信用转到Ephraim's answer 到 UIButtons 旋转后没有响应的帖子

【讨论】:

仅供参考,我最终将视图层次结构更改为:controller.view=controller.glview -> controller.parentView -> controller.banner .. parentView 是一个通用的 UIView,我用它来旋转显示器周围的横幅,因为我正在 GLES 矩阵操作中旋转 glview。

以上是关于无法在以编程方式创建的窗口中单击 iAd - 未调用bannerViewActionShouldBegin?的主要内容,如果未能解决你的问题,请参考以下文章

iOS:以编程方式在以编程方式创建的滚动视图中创建标签

允许在以模式方式显示的以编程方式创建的视图内自动旋转

Imageview 未显示在以编程方式创建的 collectionview 中

IOS5 - 如何在以编程方式创建的视图中播放视频?

如何在以编程方式创建的 UIPicker Delegate 中返回选定的值

在以编程方式创建的 UIView 层次结构之上添加子视图