These instructions work on the assumption that your app already has a banner placement correctly setup.

Here, we'll show you how to start adding some extra options.

First, we have to enable multiple placement sizes for one placement. This allows your Ad Ops team to easily differentiate the content that they would like to insert-

Below is an example of how you would implement this:

import GoogleMobileAds  
import UIKit

class ResponsiveAdDelegateViewController: UIViewController, GADAdSizeDelegate {
 
  /// The custom banner size (320x480) switch.    
  @IBOutlet weak var GADAdSizeCustomBannerSwitch: UISwitch!  

  /// The medium rectangle size (300x250) switch.    
  @IBOutlet weak var GADAdSizeMediumRectangleSwitch: UISwitch!
 
  /// The DFP banner view. It's DFPBannerView not GADBannerView right?
  var bannerView: DFPBannerView!  

  override func viewDidLoad() {
    super.viewDidLoad()
   
    bannerView = DFPBannerView(adSize: kGADAdSizeMediumRectangle)  

    bannerView.delegate = self
    // You have to set ID and what's the view controller
    // Ad Unit ID has to be set up in DV360
    bannerView.adUnitID = "/6499/example/banner"
    bannerView.rootViewController = self
   
    // Ad Size Delegate, so adView can be called in the bottom
    bannerView.adSizeDelegate = self

    // Add it into the view
    addBannerViewToView(bannerView)

    // Let's load an ad into it (whenever you want to do it)
    bannerView.load(GADRequest())
  }

  func addBannerViewToView(_ bannerView: DFPBannerView) {
    bannerView.translatesAutoresizingMaskIntoConstraints = false
    view.addSubview(bannerView)
    view.addConstraints(
      [NSLayoutConstraint(item: bannerView,
                          attribute: .bottom,
                          relatedBy: .equal,
                          toItem: bottomLayoutGuide,
                          attribute: .top,
                          multiplier: 1,
                          constant: 0),
       NSLayoutConstraint(item: bannerView,
                          attribute: .centerX,
                          relatedBy: .equal,
                          toItem: view,
                          attribute: .centerX,
                          multiplier: 1,
                          constant: 0)
      ])

     guard GADAdSizeCustomBannerSwitch.isOn ||     GADAdSizeMediumRectangleSwitch.isOn else {
       let alert = UIAlertView(title: "Load Ad Error",
          message: "Failed to load ad. Please select at least one ad size.",
          delegate: self,
          cancelButtonTitle: "OK")
       alert.alertViewStyle = .default
       alert.show()
       return
     }

     var adSizes = [NSValue]()
     
     // Let's add the valid Scroller Placement
     if GADAdSizeCustomBannerSwitch.isOn {
       let scrollerGADAdSize = GADAdSizeFromCGSize(CGSize(width: 320, height: 480))
       adSizes.append(NSValueFromGADAdSize(scrollerGADAdSize))
     }
     if GADAdSizeMediumRectangleSwitch.isOn {
       adSizes.append(NSValueFromGADAdSize(kGADAdSizeMediumRectangle))
     }

     bannerView.validAdSizes = adSizes
   }

   /// Called before the ad view changes to the new size.
   /// Initiated by the view delegate that's set via `bannerView.adSizeDelegate = self` above
   func adView(_ bannerView: DFPBannerView, willChangeAdSizeTo size: GADAdSize) {
     // The bannerView calls this method on its adSizeDelegate object before the banner updates its
     // size, allowing the application to adjust any views that may be affected by the new ad size.
     print("Make your app layout changes here, if necessary. New banner ad size will be \(size\).")
   }
}

Ref: https://developers.google.com/ad-manager/mobile-ads-sdk/ios/banner#multiple_ad_sizes

Above code has generated a AdViewDelegate that makes the placement possible to be used in two sizes. This means that based on the ad request, it chooses which creative and it's size won the bid.

This still doesn't enable us to yet have a responsive sized layout. 320 width is not anymore a standard full width as it was used to be. To make the placement responsive you have to make the frame in different sizes:


func updateBannerSize(_ bannerView: DFPBannerView, willChangeAdSizeTo size: GADAdSize) {
  let width = size.size.width
  let height = size.size.height
  let ratio = height/width
 
  let newWidth = view.bounds.width
 
  // We assume that 320 means full width and 300 means with 10px padding on left and right
  // Change the padding to what you have normal in your feed
  let feedPadding = 10
  if width != 320 {
     newWidth = newWidth - (feedPadding * 2)
  }
 
  let newHeight = ( newWidth * ratio )

  var frameRect = bannerView.frame
  frameRect.size.width = newWidth
  frameRect.size.height = newHeight
  bannerView.frame = frameRect
}

func adView(_ bannerView: DFPBannerView, willChangeAdSizeTo size: GADAdSize) {  
  ...
 
  updateBannerSize(bannerView, size)

  ...
}

Ref: https://developers.google.com/ad-manager/mobile-ads-sdk/ios/native-styles#gadadsizedelegate_protocol

Right... So we should have the whole issue with sorting out the sizes and getting correct placements in there.

Now we maybe could also open a funnel so ads can speak to the native side of the ad and vice-versa. 

This will be done through events.  

class ResponsiveAdDelegateViewController: UIViewController, GADAppEventDelegate {
     func viewDidLoad() {
          ...
          bannerView.appEventDelegate = self
          ...
     }

     func adView(_ bannerView: DFPBannerView, didReceiveAppEvent name: String,
    withInfo info: String?) {
    if name == "ad.size" {
      guard let info = info else { return }
     
      // I'm using JSON String Parser defined below, use the one you prefer
      let size: AnyObject? = info.parseJSONString
      updateBannerSize(bannerView, GADAdSizeFromCGSize(CGSize(width: size.width, height: size.height)))
    }
  }
}

Ref: https://developers.google.com/ad-manager/mobile-ads-sdk/ios/banner#app_events


JSON Parser:

extension String {

    var parseJSONString: AnyObject? {

        let data = self.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)

        if let jsonData = data {
            // Will return an object or nil if JSON decoding fails
            return NSJSONSerialization.JSONObjectWithData(jsonData, options: NSJSONReadingOptions.MutableContainers, error: nil)
        } else {
            // Lossless conversion of the string was not possible
            return nil
        }
    }
}


We should now have been able to accomplish a responsive placement that can also be controlled with an ad for perfect effect.

Thanks!

Did this answer your question?