2014-12-12 3 views
2

EDITДисплей ADBannerView с UITableViewController внутри UITabBarController

Благодаря @LeoNatan я теперь получил полный рабочий раствор. Если кто-то найдет это и захочет решить проблему, он будет доступен по адресу GitHub.

Оригинал Вопрос

Я пытаюсь получить МААШ (или любой другой вид по этому вопросу, хотя это может быть специфическими для ADBannerView), который будет отображаться только над UITabBar. Я пошел о нескольких различных способах сделать это, но не пришел к решению, что satifies следующего:

  • Работа по прошивке 7 и 8
  • Работают с и без ОВРА отображаются
  • Работает в альбомной и портретной
  • Работает на iPhone и IPad
  • UITableView сек вставках правильно обновить

Единственное решение, которое я до сих пор работала, чтобы иметь UITableView внутри UIViewController и добавив UITableView и ADBannerView к свойству viewUIViewController. Я отошел от этого по 2 причинам:

  1. UITableView не расширяющих его края ниже нижнего UITabBar
  2. мне нужно подкласс 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)

ответ

5

Лучшим решением является использование защитного кожуха вида. Используйте подкласс диспетчера представлений, в котором будут представлены как просмотр объявления, так и представление контроллера табличного представления, и добавьте контроллер представления таблицы в качестве дочернего элемента контроллера представления контейнера. Это должно правильно заботиться о вложениях содержимого. На каждом макете представления контроллера контейнера правильно расположите иерархию представления контроллера таблицы после позиционирования объявления. Если вы хотите скрыть вид объявления, просто скройте или удалите его из иерархии контейнеров и полностью разверните иерархию представлений контроллера таблиц. При работе с иерархиями не забудьте всегда использовать контроллер таблицы view, а не tableView.

Мой ответ был адаптирован в следующем GitHub репо: https://github.com/JosephDuffy/iAdContainer

+0

Это то, что я просмотрел в прошлом, но не смог получить контент, расположенный под панелью вкладок. Можете ли вы опубликовать пример этой работы? Я привязывал нижнюю часть таблицы к верхней части баннера, что, я думаю, было частью проблемы. –

+0

В случае просмотра рекламы вы все еще хотите расширить контент? Если это так, вам может понадобиться управлять содержимым и прокруткой индикаторов. Удостоверьтесь в иерархии представлений контроллера таблиц и обновите нижнюю и верхнюю вставки в соответствии с верхними и нижними вставками контейнера, добавив высоту окна просмотра в нижнюю вставку. –

+0

Это метод, который я делал в коде в исходном вопросе. В 'viewDidLayoutSubviews' я бы установил вставку содержимого, которая работает нормально, но когда устройство повернуто, высота представления баннера вычисляется после вызова' viewDidLayoutSubviews' (возможно, потому, что представление баннера не является подзором 'UITableViewController' ?). В любом случае, я не мог заставить его работать, делая это вручную. –

1

Самое лучшее, что это то, что вы скачиваете AD suite с сайта компании Apple, есть контроллер TabBar и навигационный контроллер пример локализации.
Apple предоставляет вам абстрактный контроллер представления, который может обрабатывать сам поток ADBanner без прерывания его представления, максимизируя время показа.

+0

Это было то, где я начал, но не включает автоматическую компоновку, вставки в виде таблицы, а не посмотрите на iOS 7 и выше. Если я делаю что-то неправильно или вам нужно изменить, пожалуйста, дайте мне знать. –

+0

Не факт, что AL не должен быть проблемой, авторезистирующие маски (если корневой вид активирован AL) преобразуются в ограничение. Единственная проблема «знать» на этом образце заключается в том, что при попытке скомбинировать TBC и NC система переходит в рекурсивный автоматический макет вызовов. Чтобы избежать этого, я завернул TBC в контейнер, показывающий iAD. Я понимаю, что, возможно, у вас есть проблема на дне из-за вставки, я бы предложил вам отключить расширенные края, по крайней мере, на дне. – Andrea

0

Вы можете использовать этот образец яблока https://developer.apple.com/library/ios/samplecode/iAdSuite/Introduction/Intro.html и изменить его в соответствии с вашими потребностями. Такие, как переменная bool, для которой нужно следить, когда отображается iAds или нет. В коде вы можете увидеть класс BannerViewController, который содержит всю логику. Вы также можете написать код ADmob для использования.

Смежные вопросы