[英]Display ADBannerView with UITableViewController inside UITabBarController
EDIT 编辑
Thanks to @LeoNatan I have now got a complete working solution. 感谢@LeoNatan,我现在有了一个完整的工作解决方案。 If anyone finds this and would like the solution, it's available on GitHub .
如果有人找到它并想要解决方案,则可以在GitHub上找到它 。
Original Question 原始问题
I'm trying to get iAds (or any other view for that matter, although it may be specific to ADBannerView
) to be displayed just above a UITabBar
. 我正在尝试将iAds(或其他任何视图,尽管它可能特定于
ADBannerView
)显示在UITabBar
上方。 I've gone about a few different ways of doing this, but haven't come up with a solution that satifies the following: 我已经介绍了几种不同的方法来实现此目的,但是还没有提出一种满足以下条件的解决方案:
UITableView
s insets correctly update UITableView
的插图正确更新 The only solution I have so far that has worked has been to have my UITableView
inside a UIViewController
, and adding the UITableView
and ADBannerView
to the view
property of the UIViewController
. 到目前为止,唯一有效的解决方案是将
UITableView
放在UIViewController
,并将UITableView
和ADBannerView
添加到UIViewController
的view
属性中。 I moved away from this for 2 reasons: 我出于以下两个原因而放弃了这一点:
UITableView
did not extend its edges below the bottom UITabBar
UITableView
的边缘未在底部UITabBar
下方延伸 UITableViewController
, not UIViewController
UITableViewController
而不是UIViewController
I have a bannerView
property on my AppDelegate
and a shouldShowBannerView
property to decide whether or not to show the iAd, and share a single instance. 我的
AppDelegate
上有bannerView
属性,而shouldShowBannerView
属性用于决定是否显示iAd,并共享一个实例。 The AppDelegate
then sends out notifications when iAds should be displayed or hidden (ie, when an iAd is loaded and when the user has paid to remove the iAds). 然后,
AppDelegate
会在应显示或隐藏iAd时(即,何时加载iAd以及用户为移除iAd付费时)发出通知。 The "base" of the code works as such: 代码的“基础”是这样的:
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()
}
}
}
}
I then check in my viewWillAppear:
and viewDidDisappear:
methods if an iAds is/should be displayed and calling showiAds(false)
and hideiAds()
as required. 然后,我检查我的
viewWillAppear:
和viewDidDisappear:
方法是否要显示showiAds(false)
并根据需要调用showiAds(false)
和hideiAds()
。
No matter what I do, I don't seem to be able to get it to work. 无论我做什么,我似乎都无法使它正常工作。 A couple of other things I've tried but scrapped the code for:
我尝试了其他几件事,但取消了以下代码:
UITabBarController
, which then alerts the UITableViewController
s that the iAd was shown/hidden. UITabBarController
添加iAd,然后通知UITableViewController
s iAd已显示/隐藏。 Modifying the content/scroll indicator insets did not work well, and was ofter reset by the UITableViewController
to fit above/below the navigation/tab bar. UITableViewController
经常将其重置为适合导航/选项卡栏的上方/下方。 viewDidLayoutSubviews
, but this seems very costly? viewDidLayoutSubviews
模拟(使用(top | bottom)LayoutGuide),就无法使其保持一致,但这似乎非常昂贵吗? ADBannerView
to some view from within the UITableViewController
, but it would crash on iOS 7 (something about tableView must call super -layoutSubviews) ADBannerView
从UITableViewController
内添加到某个视图中而ADBannerView
,但是在iOS 7上它会崩溃(关于tableView的事情必须调用super -layoutSubviews) EDIT 编辑
I have created a UIViewController
subclass with the intent of using it to house UITableViewControllers
via a Container View
. 我创建了一个
UIViewController
子类,目的是使用它通过Container View
来容纳UITableViewControllers
。 Here is what I have so far, followed by a couple of issues: 这是我到目前为止的内容,然后是几个问题:
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()
}
}
}
}
}
Issues so far: 到目前为止的问题:
self.view
as the superview causes a crash on rotate 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.
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.
At the request of Leo Natan I have create a repo on GitHub that I will update with any attempts I make, and explain issues here. 应Leo Natan的要求,我在GitHub上创建了一个存储库 ,我将对其进行任何尝试进行更新,并在此处说明问题。 Currently, the issues are as follows:
当前,问题如下:
First Tab: 第一个标签:
Second Tab: 第二个标签:
The best solution is to use view controller containment. 最好的解决方案是使用视图控制器遏制。 Use a view controller subclass that will house both the ad view and the table view controller's view, and add the table view controller as a child of the container view controller.
使用将包含广告视图和表视图控制器的视图的视图控制器子类,并将表视图控制器添加为容器视图控制器的子级。 This should take care of content insets correctly.
这应该正确处理内容插图。 On each layout of the container controller's view, position the table controller view hierarchy correctly after positioning the ad view.
在容器控制器视图的每个布局上,在放置广告视图之后,正确定位表控制器视图层次结构。 If you wish to hide the ad view, simply hide or remove it from the container hierarchy, and extend the table controller's view hierarchy fully.
如果要隐藏广告视图,只需将其隐藏或从容器层次结构中删除,然后完全扩展表控制器的视图层次结构。 When working with hierarchies, remember to always use the table controller's
view
and not the tableView
directly. 使用层次结构时,请记住始终使用表控制器的
view
而不是直接使用tableView
。
My answer was adapted into the following GitHub repo: https://github.com/JosephDuffy/iAdContainer 我的答案已改编为以下GitHub存储库: https : //github.com/JosephDuffy/iAdContainer
The best that is that you download the AD suite from Apple site, there are tabbar controller and navigation controller containment example. 最好的办法是从Apple网站下载AD套件 ,其中有标签栏控制器和导航控制器包含示例。
Apple provides you an abstract view controller that can handle by itself the ADBanner flow without interrupting its presentation, maximizing the showing time. Apple为您提供了一个抽象视图控制器,该控制器可以自己处理ADBanner流,而不会中断其显示,从而最大限度地延长了显示时间。
You can use this https://developer.apple.com/library/ios/samplecode/iAdSuite/Introduction/Intro.html apple sample and modified it according to your needs. 您可以使用此https://developer.apple.com/library/ios/samplecode/iAdSuite/Introduction/Intro.html苹果示例并根据需要对其进行修改。 Such as bool variable to take care of when iAds is shown or not.
例如bool变量,可用于显示或不显示iAds。 There in code you can see BannerViewController class that contains all the logic.
在代码中,您可以看到包含所有逻辑的BannerViewController类。 You can also write ADmob code there to use.
您也可以在此处编写ADmob代码以供使用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.