[英]UITableViewController inside UITabBarController inside UINavigationController
[英]Display ADBannerView with UITableViewController inside UITabBarController
編輯
感謝@LeoNatan,我現在有了一個完整的工作解決方案。 如果有人找到它並想要解決方案,則可以在GitHub上找到它 。
原始問題
我正在嘗試將iAds(或其他任何視圖,盡管它可能特定於ADBannerView
)顯示在UITabBar
上方。 我已經介紹了幾種不同的方法來實現此目的,但是還沒有提出一種滿足以下條件的解決方案:
UITableView
的插圖正確更新 到目前為止,唯一有效的解決方案是將UITableView
放在UIViewController
,並將UITableView
和ADBannerView
添加到UIViewController
的view
屬性中。 我出於以下兩個原因而放棄了這一點:
UITableView
的邊緣未在底部UITabBar
下方延伸 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
經常將其重置為適合導航/選項卡欄的上方/下方。 viewDidLayoutSubviews
模擬(使用(top | bottom)LayoutGuide),就無法使其保持一致,但這似乎非常昂貴嗎? ADBannerView
從UITableViewController
內添加到某個視圖中而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.
應Leo Natan的要求,我在GitHub上創建了一個存儲庫 ,我將對其進行任何嘗試進行更新,並在此處說明問題。 當前,問題如下:
第一個標簽:
第二個標簽:
最好的解決方案是使用視圖控制器遏制。 使用將包含廣告視圖和表視圖控制器的視圖的視圖控制器子類,並將表視圖控制器添加為容器視圖控制器的子級。 這應該正確處理內容插圖。 在容器控制器視圖的每個布局上,在放置廣告視圖之后,正確定位表控制器視圖層次結構。 如果要隱藏廣告視圖,只需將其隱藏或從容器層次結構中刪除,然后完全擴展表控制器的視圖層次結構。 使用層次結構時,請記住始終使用表控制器的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.