EDITДисплей ADBannerView с UITableViewController внутри UITabBarController
Благодаря @LeoNatan я теперь получил полный рабочий раствор. Если кто-то найдет это и захочет решить проблему, он будет доступен по адресу GitHub.
Оригинал Вопрос
Я пытаюсь получить МААШ (или любой другой вид по этому вопросу, хотя это может быть специфическими для ADBannerView
), который будет отображаться только над UITabBar
. Я пошел о нескольких различных способах сделать это, но не пришел к решению, что satifies следующего:
- Работа по прошивке 7 и 8
- Работают с и без ОВРА отображаются
- Работает в альбомной и портретной
- Работает на iPhone и IPad
UITableView
сек вставках правильно обновить
Единственное решение, которое я до сих пор работала, чтобы иметь UITableView
внутри UIViewController
и добавив UITableView
и ADBannerView
к свойству view
UIViewController
. Я отошел от этого по 2 причинам:
UITableView
не расширяющих его края ниже нижнегоUITabBar
- мне нужно подкласс
UITableViewController
, неUIViewController
У меня есть bannerView
собственность на мой AppDelegate
и shouldShowBannerView
, чтобы решить, показывать ли iAd и не использовать один экземпляр. Затем AppDelegate
отправляет уведомления, когда iAds должны отображаться или скрываться (то есть когда iAd загружается и когда пользователь платит, чтобы удалить iAds). «База» кода работает так:
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)
и hideiAds()
, как требуется МААШ.
Независимо от того, что я делаю, я, похоже, не могу заставить его работать. Несколько других вещей, которые я пробовал, но слом код:
- Добавление ОВР в
UITabBarController
, который затем сообщает об этомUITableViewController
s, что ОВР был показан/скрыт. Изменение вложений индикатора содержимого/прокрутки не получилось хорошо, и он был сброшен с помощьюUITableViewController
, чтобы соответствовать над/под панелью навигации/вкладки. - (как указано выше), самостоятельно устанавливая вкладки содержимого/прокрутки, но я не мог добиться его согласования, не пытаясь подражать (используя (сверху вниз) LayoutGuide) в
viewDidLayoutSubviews
, но это кажется очень дорогостоящим? - я сделал, в какой-то момент, он работает, добавив вид на
ADBannerView
в некоторых из вUITableViewController
, но это будет крах на IOS 7 (кое-что о Tableview должен вызвать супер -layoutSubviews)
EDIT
Я создал 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
как SuperView вызывает сбой перевернутое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, верхний вскакивает немного вверх, а нижняя часть ниже верхней части баннера.
- В представлении таблицы нет индикаторов прокрутки. Это, кажется, известная проблема, но я не могу найти решение
По просьбе Лео Натан У меня есть создать repo on GitHub, что я буду обновлять любые попытки, которые я делаю, и объяснить проблемы здесь. В настоящее время проблемы заключаются в следующем:
Первая закладка:
- Верх стола перемещается вниз, когда ОВР показано (IOS 8)
- Таблица не может быть прокручивается (IOS 7)
- Верх представление таблицы скачки, когда Iad показывает (IOS 7)
- Вращение часто нарушает смещение ОВР, скрывая его за панель вкладок (IOS 7 и 8)
Вторая вкладка:
- Там нет полосы прокрутки (IOS 7 и 8)
- Scroll врезке не установлены (IOS 7)
- Вращение часто ломает смещение ОВР, скрывая ее за вкладку бар (iOS 7 и 8)
Это то, что я просмотрел в прошлом, но не смог получить контент, расположенный под панелью вкладок. Можете ли вы опубликовать пример этой работы? Я привязывал нижнюю часть таблицы к верхней части баннера, что, я думаю, было частью проблемы. –
В случае просмотра рекламы вы все еще хотите расширить контент? Если это так, вам может понадобиться управлять содержимым и прокруткой индикаторов. Удостоверьтесь в иерархии представлений контроллера таблиц и обновите нижнюю и верхнюю вставки в соответствии с верхними и нижними вставками контейнера, добавив высоту окна просмотра в нижнюю вставку. –
Это метод, который я делал в коде в исходном вопросе. В 'viewDidLayoutSubviews' я бы установил вставку содержимого, которая работает нормально, но когда устройство повернуто, высота представления баннера вычисляется после вызова' viewDidLayoutSubviews' (возможно, потому, что представление баннера не является подзором 'UITableViewController' ?). В любом случае, я не мог заставить его работать, делая это вручную. –