在UITabBarController中使用UITableViewController显示ADBannerView

时间:2014-12-12 23:54:10

标签: ios uitableview iad

修改

感谢@LeoNatan我现在有了一个完整的解决方案。如果有人发现了这个并想要解决方案,可以在GitHub上找到。

原始问题

我试图在ADBannerView上方显示iAd(或任何其他视图,尽管可能特定于UITabBar)。我已经采用了几种不同的方法来实现这一目标,但我们还没有找到满足以下条件的解决方案:

  • 适用于iOS 7和8
  • 无论是否显示iAd都可以使用
  • 以风景和肖像作品
  • 适用于iPhone和iPad
  • UITableView s insets正确更新

我迄今为止唯一有效的解决方案是将UITableView置于UIViewController内,并将UITableViewADBannerView添加到{{1} view的属性。我离开了这个有两个原因:

  1. UIViewController未将其边缘延伸到底部UITableView
  2. 下方
  3. 我需要继承UITabBar,而不是UITableViewController
  4. 我的UIViewControllerbannerView属性上有AppDelegate属性,用于决定是否显示iAd,以及共享单个实例。然后,shouldShowBannerView会在显示或隐藏iAd时发出通知(即,当加载iAd时以及用户付费移除iAd时)。 "基地"代码的工作原理如下:

    AppDelegate

    然后我会检查我的func showiAds(animated: Bool) { if !self.showingiAd { let delegate = UIApplication.sharedApplication().delegate as AppDelegate if let bannerView = delegate.bannerView { println("Showing iAd") self.showingiAd = true if (bannerView.superview != self.view) { bannerView.removeFromSuperview() } // let bannersSuperview = self.view.superview! // Bottom inset incorrect let bannersSuperview = self.view // Banner is shown at the top screen. Crashes on iOS 7 (at bannersSuperview.layoutIfNeeded()) // let bannersSuperview = self.tableView // The is the same as self.view (duh) // let bannersSuperview = self.tabBarController!.view // Bottom inset incorrect // Added the view and the left/right constraints allow for the proper height // to be returned when bannerView.frame.size.height is called (iOS 7 fix mainly) bannersSuperview.addSubview(bannerView) bannersSuperview.addConstraints([ NSLayoutConstraint(item: bannerView, attribute: .Left, relatedBy: .Equal, toItem: bannersSuperview, attribute: .Left, multiplier: 1, constant: 0), NSLayoutConstraint(item: bannerView, attribute: .Right, relatedBy: .Equal, toItem: bannersSuperview, attribute: .Right, multiplier: 1, constant: 0), ]) bannersSuperview.layoutIfNeeded() let bannerViewHeight = bannerView.frame.size.height var offset: CGFloat = -self.bottomLayoutGuide.length if (UIDevice.currentDevice().systemVersion as NSString).floatValue < 8 { // Seems to be needed for some reason offset -= bannerViewHeight } let bannerBottomConstraint = NSLayoutConstraint(item: bannerView, attribute: .Bottom, relatedBy: .Equal, toItem: bannersSuperview, attribute: .Bottom, multiplier: 1, constant: offset + bannerViewHeight) // self.bannerBottomConstraint = bannerBottomConstraint bannersSuperview.addConstraint(bannerBottomConstraint) bannersSuperview.layoutSubviews() // bannerSuperview.setNeedsLayout() bannersSuperview.layoutIfNeeded() // Previously, this values was the height of the banner view, so that it starts off screen. // Setting this to 0 and then doing an animation makes it slide in from below bannerBottomConstraint.constant = offset bannersSuperview.setNeedsUpdateConstraints() UIView.animateWithDuration(animated ? 10 : 0, animations: { () -> Void in // Calling layoutIfNeeded here will animate the layout constraint cosntant change made above bannersSuperview.layoutIfNeeded() }) } else { println("Cannot show iAd when bannerView is nil") } } } func hideiAds() { if self.showingiAd { self.showingiAd = false let delegate = UIApplication.sharedApplication().delegate as AppDelegate if let bannerView = delegate.bannerView { if bannerView.superview == self.view { bannerView.removeFromSuperview() } } } } viewWillAppear:方法是否应该显示iAds,并根据需要调用viewDidDisappear:showiAds(false)

    无论我做什么,我似乎都无法让它发挥作用。我尝试过的其他一些事情却废弃了以下代码:

    • hideiAds()中添加iAd,然后警告显示/隐藏iAd的UITabBarController。修改内容/滚动指示符插入不正常,并由UITableViewController更改为适合导航/标签栏上方/下方。
    • (如上所述)将内容/滚动指示器设置为自我,但如果不尝试在UITableViewController中模拟(使用(顶部|底部)布局指南),我无法使其保持一致,但这看起来非常昂贵?< / LI>
    • 我曾经在viewDidLayoutSubviews内添加了ADBannerView某些视图,但是它确实在iOS 7上崩溃了tableView必须调用super -layoutSubviews)

    修改

    我创建了一个UITableViewController子类,目的是通过UIViewController使用它来容纳UITableViewControllers。以下是我到目前为止所做的一些问题:

    Container View

    到目前为止的问题:

    • 使用class AdvertContainerViewController: UIViewController { var tableViewController: UITableViewController? var showingiAd = false var bannerBottomConstraint: NSLayoutConstraint? private var bannerTopOffset: CGFloat { get { var offset: CGFloat = 0 if let tabBar = self.tabBarController?.tabBar { offset -= CGRectGetHeight(tabBar.frame) } if let bannerView = AppDelegate.instance.bannerView { let bannerViewHeight = bannerView.frame.size.height offset -= bannerViewHeight } return offset } } override func viewDidLoad() { super.viewDidLoad() if self.childViewControllers.count > 0 { if let tableViewController = self.childViewControllers[0] as? UITableViewController { self.tableViewController = tableViewController tableViewController.automaticallyAdjustsScrollViewInsets = false self.navigationItem.title = tableViewController.navigationItem.title } } } override func viewWillAppear(animated: Bool) { super.viewWillAppear(animated) if AppDelegate.instance.shouldShowBannerView { self.showiAds(false) } } override func viewDidAppear(animated: Bool) { super.viewDidAppear(animated) let delegate = AppDelegate.instance NSNotificationCenter.defaultCenter().addObserver(self, selector: "showiAds", name: "BannerViewDidLoadAd", object: delegate) NSNotificationCenter.defaultCenter().addObserver(self, selector: "hideiAds", name: "RemoveBannerAds", object: delegate) } override func viewDidDisappear(animated: Bool) { super.viewDidDisappear(animated) if self.showingiAd { self.hideiAds() } } override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() println("View did layout subviews") if self.showingiAd { if let bannerView = AppDelegate.instance.bannerView { let bannerViewHeight = CGRectGetHeight(bannerView.frame) if let bottomConstraint = self.bannerBottomConstraint { let bannerTopOffset = self.bottomLayoutGuide.length + bannerViewHeight if bottomConstraint.constant != bannerTopOffset { println("Setting banner top offset to \(bannerTopOffset)") bottomConstraint.constant = -bannerTopOffset bannerView.superview?.setNeedsUpdateConstraints() bannerView.superview?.updateConstraintsIfNeeded() } } println("Bottom layout guide is \(self.bottomLayoutGuide.length)") let insets = UIEdgeInsetsMake(self.topLayoutGuide.length, 0, self.bottomLayoutGuide.length + bannerViewHeight, 0) self.updateTableViewInsetsIfRequired(insets) } } } private func updateTableViewInsetsIfRequired(insets: UIEdgeInsets) { if let tableView = self.tableViewController?.tableView { if !UIEdgeInsetsEqualToEdgeInsets(tableView.contentInset, insets) { println("Updating content insets to \(insets.top), \(insets.bottom)") tableView.contentInset = insets } if !UIEdgeInsetsEqualToEdgeInsets(tableView.scrollIndicatorInsets, insets) { println("Updating scroll insets to \(insets.top), \(insets.bottom)") tableView.scrollIndicatorInsets = insets } } } func showiAds() { self.showiAds(true) // self.showiAds(false) } func showiAds(animated: Bool) { if !self.showingiAd { let delegate = UIApplication.sharedApplication().delegate as AppDelegate if let bannerView = delegate.bannerView { println("Showing iAd") self.showingiAd = true if (bannerView.superview != self.view) { bannerView.removeFromSuperview() } let bannersSuperview = self.view.superview! // Added the view and the left/right constraints allow for the proper height // to be returned when bannerView.frame.size.height is called (iOS 7 fix mainly) bannersSuperview.addSubview(bannerView) bannersSuperview.addConstraints([ NSLayoutConstraint(item: bannerView, attribute: .Left, relatedBy: .Equal, toItem: bannersSuperview, attribute: .Left, multiplier: 1, constant: 0), NSLayoutConstraint(item: bannerView, attribute: .Right, relatedBy: .Equal, toItem: bannersSuperview, attribute: .Right, multiplier: 1, constant: 0), ]) bannersSuperview.layoutIfNeeded() let bannerBottomConstraint = NSLayoutConstraint(item: bannerView, attribute: .Top, relatedBy: .Equal, toItem: bannersSuperview, attribute: .Bottom, multiplier: 1, constant: 0) self.bannerBottomConstraint = bannerBottomConstraint bannersSuperview.addConstraint(bannerBottomConstraint) bannersSuperview.layoutSubviews() bannersSuperview.layoutIfNeeded() let topInset = self.navigationController?.navigationBar.frame.size.height ?? 0 let insets = UIEdgeInsetsMake(topInset, 0, -self.bannerTopOffset, 0) // Previously, this values was the height of the banner view, so that it starts off screen. // Setting this to 0 and then doing an animation makes it slide in from below bannerBottomConstraint.constant = self.bannerTopOffset bannersSuperview.setNeedsUpdateConstraints() UIView.animateWithDuration(animated ? 0.5 : 0, animations: { () -> Void in // Calling layoutIfNeeded here will animate the layout constraint cosntant change made above self.updateTableViewInsetsIfRequired(insets) bannersSuperview.layoutIfNeeded() }) } else { println("Cannot show iAd when bannerView is nil") } } } func hideiAds() { if self.showingiAd { self.showingiAd = false let delegate = UIApplication.sharedApplication().delegate as AppDelegate if let bannerView = delegate.bannerView { if bannerView.superview == self.view { bannerView.removeFromSuperview() } } } } } 作为超级视图会导致轮播self.view
    • 崩溃
    • 我没有正确计算内容插入内容;当显示iAd时,顶部略微向上跳跃,底部在横幅顶部下方
    • 表格视图不显示滚动指示符。这似乎是一个已知问题,但我找不到解决方案

    应Leo Natan的请求,我创建了一个repo on GitHub,我将根据我的任何尝试进行更新,并在此解释问题。目前,问题如下:

    第一个标签:

    • 当显示iAd时,表顶部向下移动(iOS 8)
    • 无法滚动表格(iOS 7)
    • 当iAd显示(iOS 7)
    • 时,表格视图的顶部跳转
    • 旋转经常会破坏iAd的偏移量,将其隐藏在标签栏后面(iOS 7和8)

    第二个标签:

    • 没有滚动条(iOS 7和8)
    • 滚动插入未设置(iOS 7)
    • 旋转经常会破坏iAd的偏移量,将其隐藏在标签栏后面(iOS 7和8)

3 个答案:

答案 0 :(得分:5)

最佳解决方案是使用视图控制器包含。使用视图控制器子类,它将容纳广告视图和表视图控制器的视图,并将表视图控制器添加为容器视图控制器的子视图。这应该正确地处理内容插入。在容器控制器视图的每个布局上,在定位广告视图后正确定位表控制器视图层次结构。如果您希望隐藏广告视图,只需在容器层次结构中隐藏或删除它,并完全扩展表控制器的视图层次结构。使用层次结构时,请记住始终使用表格控制器view而不是tableView直接使用。

我的回答被改编成以下GitHub回购: https://github.com/JosephDuffy/iAdContainer

答案 1 :(得分:1)

最好的是从Apple网站下载AD suite,有tabbar控制器和导航控制器包含示例。
Apple为您提供了一个抽象视图控制器,它可以自行处理ADBanner流程,而不会中断其显示,从而最大限度地延长显示时间。

答案 2 :(得分:0)

您可以使用此https://developer.apple.com/library/ios/samplecode/iAdSuite/Introduction/Intro.html苹果样本并根据您的需要进行修改。例如bool变量,以便在显示或不显示iAd时进行处理。 在代码中,您可以看到包含所有逻辑的BannerViewController类。您也可以在那里编写ADmob代码以供使用。