簡體   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