繁体   English   中英

在UITabBarController内部使用UITableViewController显示ADBannerView

[英]Display ADBannerView with UITableViewController inside UITabBarController

编辑

感谢@LeoNatan,我现在有了一个完整的工作解决方案。 如果有人找到它并想​​要解决方案,则可以在GitHub找到它

原始问题

我正在尝试将iAds(或其他任何视图,尽管它可能特定于ADBannerView )显示在UITabBar上方。 我已经介绍了几种不同的方法来实现此目的,但是还没有提出一种满足以下条件的解决方案:

  • 适用于iOS 7和8
  • 在显示和不显示iAd的情况下均可使用
  • 适用于风景和肖像
  • 适用于iPhone和iPad
  • UITableView的插图正确更新

到目前为止,唯一有效的解决方案是将UITableView放在UIViewController ,并将UITableViewADBannerView添加到UIViewControllerview属性中。 我出于以下两个原因而放弃了这一点:

  1. UITableView的边缘未在底部UITabBar下方延伸
  2. 我需要UITableViewController而不是UIViewController

我的AppDelegate上有bannerView属性,而shouldShowBannerView属性用于决定是否显示iAd,并共享一个实例。 然后, AppDelegate会在应显示或隐藏iAd时(即,何时加载iAd以及用户为移除iAd付费时)发出通知。 代码的“基础”是这样的:

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:viewDidDisappear:方法是否要显示showiAds(false)并根据需要调用showiAds(false)hideiAds()

无论我做什么,我似乎都无法使它正常工作。 我尝试了其他几件事,但取消了以下代码:

  • UITabBarController添加iAd,然后通知UITableViewController s iAd已显示/隐藏。 修改内容/滚动指示器的插入效果不佳,并且UITableViewController经常将其重置为适合导航/选项卡栏的上方/下方。
  • (如上所述)设置content / scroll指标会使我自己插入,但是如果不尝试在viewDidLayoutSubviews模拟(使用(top | bottom)LayoutGuide),就无法使其保持一致,但这似乎非常昂贵吗?
  • 我确实做到了,它通过将ADBannerViewUITableViewController内添加到某个视图中而ADBannerView ,但是在iOS 7上它会崩溃(关于tableView的事情必须调用super -layoutSubviews)

编辑

我创建了一个UIViewController子类,目的是使用它通过Container View来容纳UITableViewControllers 这是我到目前为止的内容,然后是几个问题:

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作为上海华引起的旋转碰撞Auto Layout still required after sending -viewDidLayoutSubviews to the view controller. Gathered.AdvertContainerViewController's implementation needs to send -layoutSubviews to the view to invoke auto layout. Auto Layout still required after sending -viewDidLayoutSubviews to the view controller. Gathered.AdvertContainerViewController's implementation needs to send -layoutSubviews to the view to invoke auto layout.
  • 我没有正确计算内容插图; 显示iAd时,顶部略微跳起,底部在横幅顶部下方
  • 表格视图未显示滚动指示器。 这似乎是一个已知问题,但我找不到解决方案

应Leo Natan的要求,我在GitHub上创建了一个存储 ,我将对其进行任何尝试进行更新,并在此处说明问题。 当前,问题如下:

第一个标签:

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

第二个标签:

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

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

我的答案已改编为以下GitHub存储库: https : //github.com/JosephDuffy/iAdContainer

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM