title: How To Hide Admob UIViewController Until Loaded In SwiftUI
body: <p>I have a UIViewController wrapped inside of a UIViewControllerRepresnetable. I followed a tutorial that displays Admob Native ads inside of SwiftUI located here <a href="https://github.com/sakurabird/iOS-Admob-SwiftUI-example" rel="nofollow noreferrer">https://github.com/sakurabird/iOS-Admob-SwiftUI-example</a>. Unfortunately, the way it loads right now is that it loads all the default data and then the ad loads. The way I would like it to load is to show a loader or even better yet, hide it until it's ready. In that same vein, if an ad doesn't load I would probably wanna keep it hidden, so I may need to account for that too.</p>
  <p>My code looks like this:</p>
  <p>DashboardView.switt</p>
  <pre><code>struct DashboardView: View {
       var body: some View {
          GADNativeViewControllerWrapper()
            .frame(height: 140)
            .padding(.horizontal, 10)
       }
   }
  </code></pre>
  <p>GADNativeViewControllerWrapper.swift</p>
  <pre><code>import UIKit
  import SwiftUI
  import GoogleMobileAds
  
  struct GADNativeViewControllerWrapper : UIViewControllerRepresentable {
  
    func makeUIViewController(context: Context) -&gt; UIViewController {
        let viewController = GADNativeViewController()
  
        print(&quot;View Controller Loading&quot;)
        return viewController
    }
  
    func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
    }
  }
  </code></pre>
  <p>GADNativeViewController.swift</p>
  <pre><code>// This sample code is based on Google's examples
  // https://github.com/googleads/googleads-mobile-ios-examples/releases/tag/7.22
  class GADNativeViewController: UIViewController {
  
    /// The height constraint applied to the ad view, where necessary.
    var heightConstraint: NSLayoutConstraint?
  
    /// The ad loader. You must keep a strong reference to the GADAdLoader during the ad loading
    /// process.
    var adLoader: GADAdLoader!
  
    /// The native ad view that is being presented.
    var nativeAdView: GADNativeAdView!
  
    /// The ad unit ID.
    let adUnitID = &quot;ca-app-pub-5369590807882218/4925619859&quot;
          
      var loading: Bool = true
      
  
      
      init() {
          super.init(nibName: nil, bundle: nil)
      }
      
      required init?(coder aDecoder: NSCoder) {
              fatalError(&quot;init(coder:) has not been implemented&quot;)
      }
      
    override func viewDidLoad() {
      super.viewDidLoad()
        
      guard
        let nibObjects = Bundle.main.loadNibNamed(&quot;NativeAdView&quot;, owner: nil, options: nil),
        let adView = nibObjects.first as? GADNativeAdView
      else {
        assert(false, &quot;Could not load nib file for adView&quot;)
      }
  
        
      setAdView(adView)
      refreshAd()
    }
  
    func setAdView(_ view: GADNativeAdView) {
      nativeAdView = view
      self.view.addSubview(nativeAdView)
      nativeAdView.translatesAutoresizingMaskIntoConstraints = false
  
      // Layout constraints for positioning the native ad view to stretch the entire width and height
      // of the nativeAdPlaceholder.
      let viewDictionary = [&quot;_nativeAdView&quot;: nativeAdView!]
      self.view.addConstraints(
        NSLayoutConstraint.constraints(
          withVisualFormat: &quot;H:|[_nativeAdView]|&quot;,
          options: NSLayoutConstraint.FormatOptions(rawValue: 0), metrics: nil, views: viewDictionary)
      )
      self.view.addConstraints(
        NSLayoutConstraint.constraints(
          withVisualFormat: &quot;V:|[_nativeAdView]|&quot;,
          options: NSLayoutConstraint.FormatOptions(rawValue: 0), metrics: nil, views: viewDictionary)
      )
    }
  
    // MARK: - Actions
    /// Refreshes the native ad.
    func refreshAd() {
      adLoader = GADAdLoader(
        adUnitID: adUnitID, rootViewController: self,
        adTypes: [.native], options: nil)
      adLoader.delegate = self
      adLoader.load(GADRequest())
    }
  
    /// Returns a `UIImage` representing the number of stars from the given star rating; returns `nil`
    /// if the star rating is less than 3.5 stars.
    func imageOfStars(from starRating: NSDecimalNumber?) -&gt; UIImage? {
      guard let rating = starRating?.doubleValue else {
        return nil
      }
      if rating &gt;= 5 {
        return UIImage(named: &quot;stars_5&quot;)
      } else if rating &gt;= 4.5 {
        return UIImage(named: &quot;stars_4_5&quot;)
      } else if rating &gt;= 4 {
        return UIImage(named: &quot;stars_4&quot;)
      } else if rating &gt;= 3.5 {
        return UIImage(named: &quot;stars_3_5&quot;)
      } else {
        return nil
      }
    }
  }
  
  extension GADNativeViewController: GADVideoControllerDelegate {
  
    func videoControllerDidEndVideoPlayback(_ videoController: GADVideoController) {
      print(&quot;Video playback has ended.&quot;)
    }
  }
  
  extension GADNativeViewController: GADNativeAdLoaderDelegate {
  
    func adLoader(_ adLoader: GADAdLoader, didReceive nativeAd: GADNativeAd) {
      // Set ourselves as the native ad delegate to be notified of native ad events.
      nativeAd.delegate = self
  
        // Deactivate the height constraint that was set when the previous video ad loaded.
      heightConstraint?.isActive = false
  
      // Populate the native ad view with the native ad assets.
      // The headline and mediaContent are guaranteed to be present in every native ad.
      (nativeAdView.headlineView as? UILabel)?.text = nativeAd.headline
      nativeAdView.mediaView?.mediaContent = nativeAd.mediaContent
  
      // Some native ads will include a video asset, while others do not. Apps can use the
      // GADVideoController's hasVideoContent property to determine if one is present, and adjust their
      // UI accordingly.
      let mediaContent = nativeAd.mediaContent
      if mediaContent.hasVideoContent {
        // By acting as the delegate to the GADVideoController, this ViewController receives messages
        // about events in the video lifecycle.
        mediaContent.videoController.delegate = self
        print(&quot;Ad contains a video asset.&quot;)
      } else {
        print(&quot;Ad does not contain a video.&quot;)
      }
  
      // This app uses a fixed width for the GADMediaView and changes its height to match the aspect
      // ratio of the media it displays.
      if let mediaView = nativeAdView.mediaView, nativeAd.mediaContent.aspectRatio &gt; 0 {
        heightConstraint = NSLayoutConstraint(
          item: mediaView,
          attribute: .height,
          relatedBy: .equal,
          toItem: mediaView,
          attribute: .width,
          multiplier: CGFloat(1 / nativeAd.mediaContent.aspectRatio),
          constant: 0)
        heightConstraint?.isActive = true
      }
  
      // These assets are not guaranteed to be present. Check that they are before
      // showing or hiding them.
      (nativeAdView.bodyView as? UILabel)?.text = nativeAd.body
      nativeAdView.bodyView?.isHidden = nativeAd.body == nil
  
      (nativeAdView.callToActionView as? UIButton)?.setTitle(nativeAd.callToAction, for: .normal)
      nativeAdView.callToActionView?.isHidden = nativeAd.callToAction == nil
  
      (nativeAdView.iconView as? UIImageView)?.image = nativeAd.icon?.image
      nativeAdView.iconView?.isHidden = nativeAd.icon == nil
  
      (nativeAdView.starRatingView as? UIImageView)?.image = imageOfStars(from: nativeAd.starRating)
      nativeAdView.starRatingView?.isHidden = nativeAd.starRating == nil
  
      (nativeAdView.storeView as? UILabel)?.text = nativeAd.store
      nativeAdView.storeView?.isHidden = nativeAd.store == nil
  
      (nativeAdView.priceView as? UILabel)?.text = nativeAd.price
      nativeAdView.priceView?.isHidden = nativeAd.price == nil
  
      (nativeAdView.advertiserView as? UILabel)?.text = nativeAd.advertiser
      nativeAdView.advertiserView?.isHidden = nativeAd.advertiser == nil
  
      // In order for the SDK to process touch events properly, user interaction should be disabled.
      nativeAdView.callToActionView?.isUserInteractionEnabled = false
  
        nativeAdView.callToActionView?.layer.cornerRadius = 5
  
        
      // Associate the native ad view with the native ad object. This is
      // required to make the ad clickable.
      // Note: this should always be done after populating the ad views.
      nativeAdView.nativeAd = nativeAd
    }
  
    func adLoader(_ adLoader: GADAdLoader, didFailToReceiveAdWithError error: Error) {
      print(&quot;\(adLoader) failed with error: \(error.localizedDescription)&quot;)
    }
  }
  
  // MARK: - GADNativeAdDelegate implementation
  extension GADNativeViewController: GADNativeAdDelegate {
  
    func nativeAdDidRecordClick(_ nativeAd: GADNativeAd) {
      print(&quot;\(#function) called&quot;)
    }
  
    func nativeAdDidRecordImpression(_ nativeAd: GADNativeAd) {
      print(&quot;\(#function) called&quot;)
    }
  
    func nativeAdWillPresentScreen(_ nativeAd: GADNativeAd) {
      print(&quot;\(#function) called&quot;)
    }
  
    func nativeAdWillDismissScreen(_ nativeAd: GADNativeAd) {
      print(&quot;\(#function) called&quot;)
    }
  
    func nativeAdDidDismissScreen(_ nativeAd: GADNativeAd) {
      print(&quot;\(#function) called&quot;)
    }
  
    func nativeAdIsMuted(_ nativeAd: GADNativeAd) {
      print(&quot;\(#function) called&quot;)
    }
  }
  </code></pre>
  <p>NativeAdView.xib</p>
  <pre><code>&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
  &lt;document type=&quot;com.apple.InterfaceBuilder3.CocoaTouch.XIB&quot; version=&quot;3.0&quot; toolsVersion=&quot;20037&quot; targetRuntime=&quot;iOS.CocoaTouch&quot; propertyAccessControl=&quot;none&quot; useAutolayout=&quot;YES&quot; colorMatched=&quot;YES&quot;&gt;
      &lt;device id=&quot;retina4_7&quot; orientation=&quot;portrait&quot; appearance=&quot;light&quot;/&gt;
      &lt;dependencies&gt;
          &lt;deployment version=&quot;2048&quot; identifier=&quot;iOS&quot;/&gt;
          &lt;plugIn identifier=&quot;com.apple.InterfaceBuilder.IBCocoaTouchPlugin&quot; version=&quot;20020&quot;/&gt;
          &lt;capability name=&quot;System colors in document resources&quot; minToolsVersion=&quot;11.0&quot;/&gt;
          &lt;capability name=&quot;documents saved in the Xcode 8 format&quot; minToolsVersion=&quot;8.0&quot;/&gt;
      &lt;/dependencies&gt;
      &lt;objects&gt;
          &lt;placeholder placeholderIdentifier=&quot;IBFilesOwner&quot; id=&quot;-1&quot; userLabel=&quot;File's Owner&quot;/&gt;
          &lt;placeholder placeholderIdentifier=&quot;IBFirstResponder&quot; id=&quot;-2&quot; customClass=&quot;UIResponder&quot;/&gt;
          &lt;view contentMode=&quot;scaleToFill&quot; layoutMarginsFollowReadableWidth=&quot;YES&quot; id=&quot;iN0-l3-epB&quot; customClass=&quot;GADNativeAdView&quot;&gt;
              &lt;rect key=&quot;frame&quot; x=&quot;0.0&quot; y=&quot;0.0&quot; width=&quot;375&quot; height=&quot;667&quot;/&gt;
              &lt;autoresizingMask key=&quot;autoresizingMask&quot;/&gt;
              &lt;subviews&gt;
                  &lt;label opaque=&quot;NO&quot; userInteractionEnabled=&quot;NO&quot; contentMode=&quot;left&quot; horizontalHuggingPriority=&quot;251&quot; verticalHuggingPriority=&quot;251&quot; verticalCompressionResistancePriority=&quot;751&quot; text=&quot;Body that is really really long and can take up to two lines or sometimes even more.&quot; textAlignment=&quot;justified&quot; lineBreakMode=&quot;tailTruncation&quot; numberOfLines=&quot;0&quot; baselineAdjustment=&quot;alignBaselines&quot; adjustsFontSizeToFit=&quot;NO&quot; translatesAutoresizingMaskIntoConstraints=&quot;NO&quot; id=&quot;PEQ-D9-2Vv&quot;&gt;
                      &lt;rect key=&quot;frame&quot; x=&quot;0.0&quot; y=&quot;60&quot; width=&quot;375&quot; height=&quot;33.5&quot;/&gt;
                      &lt;fontDescription key=&quot;fontDescription&quot; type=&quot;system&quot; pointSize=&quot;14&quot;/&gt;
                      &lt;nil key=&quot;textColor&quot;/&gt;
                      &lt;nil key=&quot;highlightedColor&quot;/&gt;
                  &lt;/label&gt;
                  &lt;label opaque=&quot;NO&quot; userInteractionEnabled=&quot;NO&quot; contentMode=&quot;left&quot; verticalHuggingPriority=&quot;251&quot; horizontalCompressionResistancePriority=&quot;751&quot; misplaced=&quot;YES&quot; text=&quot;Headline&quot; lineBreakMode=&quot;tailTruncation&quot; baselineAdjustment=&quot;alignBaselines&quot; adjustsFontSizeToFit=&quot;NO&quot; translatesAutoresizingMaskIntoConstraints=&quot;NO&quot; id=&quot;beR-eV-DX1&quot;&gt;
                      &lt;rect key=&quot;frame&quot; x=&quot;0.0&quot; y=&quot;6&quot; width=&quot;375&quot; height=&quot;21&quot;/&gt;
                      &lt;fontDescription key=&quot;fontDescription&quot; type=&quot;system&quot; pointSize=&quot;17&quot;/&gt;
                      &lt;nil key=&quot;textColor&quot;/&gt;
                      &lt;nil key=&quot;highlightedColor&quot;/&gt;
                  &lt;/label&gt;
                  &lt;label opaque=&quot;NO&quot; userInteractionEnabled=&quot;NO&quot; contentMode=&quot;left&quot; horizontalHuggingPriority=&quot;251&quot; verticalHuggingPriority=&quot;251&quot; misplaced=&quot;YES&quot; text=&quot;Advertiser&quot; lineBreakMode=&quot;tailTruncation&quot; baselineAdjustment=&quot;alignBaselines&quot; adjustsFontSizeToFit=&quot;NO&quot; translatesAutoresizingMaskIntoConstraints=&quot;NO&quot; id=&quot;GTT-Yh-eSq&quot;&gt;
                      &lt;rect key=&quot;frame&quot; x=&quot;0.0&quot; y=&quot;30&quot; width=&quot;375&quot; height=&quot;17&quot;/&gt;
                      &lt;fontDescription key=&quot;fontDescription&quot; type=&quot;system&quot; pointSize=&quot;14&quot;/&gt;
                      &lt;nil key=&quot;textColor&quot;/&gt;
                      &lt;nil key=&quot;highlightedColor&quot;/&gt;
                  &lt;/label&gt;
                  &lt;button opaque=&quot;NO&quot; userInteractionEnabled=&quot;NO&quot; contentMode=&quot;scaleToFill&quot; misplaced=&quot;YES&quot; contentHorizontalAlignment=&quot;center&quot; contentVerticalAlignment=&quot;center&quot; buttonType=&quot;system&quot; lineBreakMode=&quot;middleTruncation&quot; translatesAutoresizingMaskIntoConstraints=&quot;NO&quot; id=&quot;E5w-YA-UY8&quot; customClass=&quot;SubmitButton&quot;&gt;
                      &lt;rect key=&quot;frame&quot; x=&quot;275&quot; y=&quot;106&quot; width=&quot;100&quot; height=&quot;35&quot;/&gt;
                      &lt;color key=&quot;backgroundColor&quot; red=&quot;0.26666666666666666&quot; green=&quot;0.51832170050000004&quot; blue=&quot;0.274670741&quot; alpha=&quot;1&quot; colorSpace=&quot;custom&quot; customColorSpace=&quot;displayP3&quot;/&gt;
                      &lt;fontDescription key=&quot;fontDescription&quot; type=&quot;system&quot; pointSize=&quot;18&quot;/&gt;
                      &lt;color key=&quot;tintColor&quot; red=&quot;0.26666666666666666&quot; green=&quot;0.51832170050000004&quot; blue=&quot;0.274670741&quot; alpha=&quot;0.0&quot; colorSpace=&quot;custom&quot; customColorSpace=&quot;displayP3&quot;/&gt;
                      &lt;inset key=&quot;contentEdgeInsets&quot; minX=&quot;15&quot; minY=&quot;5&quot; maxX=&quot;15&quot; maxY=&quot;6&quot;/&gt;
                      &lt;state key=&quot;normal&quot; title=&quot;Install&quot;&gt;
                          &lt;color key=&quot;titleColor&quot; systemColor=&quot;tertiarySystemBackgroundColor&quot;/&gt;
                      &lt;/state&gt;
                  &lt;/button&gt;
              &lt;/subviews&gt;
              &lt;constraints&gt;
                  &lt;constraint firstItem=&quot;GTT-Yh-eSq&quot; firstAttribute=&quot;leading&quot; secondItem=&quot;iN0-l3-epB&quot; secondAttribute=&quot;leading&quot; id=&quot;4ow-he-vUe&quot;/&gt;
                  &lt;constraint firstAttribute=&quot;trailing&quot; secondItem=&quot;PEQ-D9-2Vv&quot; secondAttribute=&quot;trailing&quot; id=&quot;HDn-Hh-JJK&quot;/&gt;
                  &lt;constraint firstItem=&quot;PEQ-D9-2Vv&quot; firstAttribute=&quot;top&quot; secondItem=&quot;GTT-Yh-eSq&quot; secondAttribute=&quot;bottom&quot; constant=&quot;14&quot; id=&quot;Hdp-H1-1e9&quot;/&gt;
                  &lt;constraint firstAttribute=&quot;trailing&quot; secondItem=&quot;E5w-YA-UY8&quot; secondAttribute=&quot;trailing&quot; id=&quot;N3n-hU-4aB&quot;/&gt;
                  &lt;constraint firstItem=&quot;beR-eV-DX1&quot; firstAttribute=&quot;leading&quot; secondItem=&quot;iN0-l3-epB&quot; secondAttribute=&quot;leading&quot; id=&quot;WQo-hq-oGz&quot;/&gt;
                  &lt;constraint firstAttribute=&quot;trailing&quot; secondItem=&quot;GTT-Yh-eSq&quot; secondAttribute=&quot;trailing&quot; id=&quot;ZBZ-PE-pDA&quot;/&gt;
                  &lt;constraint firstItem=&quot;E5w-YA-UY8&quot; firstAttribute=&quot;top&quot; secondItem=&quot;iN0-l3-epB&quot; secondAttribute=&quot;top&quot; constant=&quot;106&quot; id=&quot;cQC-Sw-PKa&quot;/&gt;
                  &lt;constraint firstItem=&quot;PEQ-D9-2Vv&quot; firstAttribute=&quot;leading&quot; secondItem=&quot;iN0-l3-epB&quot; secondAttribute=&quot;leading&quot; id=&quot;fhj-jN-weP&quot;/&gt;
                  &lt;constraint firstAttribute=&quot;trailing&quot; secondItem=&quot;GTT-Yh-eSq&quot; secondAttribute=&quot;trailing&quot; id=&quot;pbg-00-jfp&quot;/&gt;
                  &lt;constraint firstItem=&quot;E5w-YA-UY8&quot; firstAttribute=&quot;top&quot; secondItem=&quot;PEQ-D9-2Vv&quot; secondAttribute=&quot;bottom&quot; constant=&quot;12.5&quot; id=&quot;qNG-LJ-Hgd&quot;/&gt;
                  &lt;constraint firstItem=&quot;beR-eV-DX1&quot; firstAttribute=&quot;top&quot; secondItem=&quot;iN0-l3-epB&quot; secondAttribute=&quot;top&quot; id=&quot;td0-mF-Qti&quot;/&gt;
                  &lt;constraint firstItem=&quot;beR-eV-DX1&quot; firstAttribute=&quot;leading&quot; secondItem=&quot;GTT-Yh-eSq&quot; secondAttribute=&quot;trailing&quot; constant=&quot;-375&quot; id=&quot;xc0-pI-Jk1&quot;/&gt;
                  &lt;constraint firstItem=&quot;GTT-Yh-eSq&quot; firstAttribute=&quot;top&quot; secondItem=&quot;beR-eV-DX1&quot; secondAttribute=&quot;bottom&quot; constant=&quot;8&quot; symbolic=&quot;YES&quot; id=&quot;yte-Yr-EaU&quot;/&gt;
              &lt;/constraints&gt;
              &lt;connections&gt;
                  &lt;outlet property=&quot;advertiserView&quot; destination=&quot;GTT-Yh-eSq&quot; id=&quot;bY8-5O-6fF&quot;/&gt;
                  &lt;outlet property=&quot;bodyView&quot; destination=&quot;PEQ-D9-2Vv&quot; id=&quot;Gpd-Q6-Byv&quot;/&gt;
                  &lt;outlet property=&quot;callToActionView&quot; destination=&quot;E5w-YA-UY8&quot; id=&quot;RCf-yK-s1x&quot;/&gt;
                  &lt;outlet property=&quot;headlineView&quot; destination=&quot;beR-eV-DX1&quot; id=&quot;d1E-ed-yel&quot;/&gt;
              &lt;/connections&gt;
              &lt;point key=&quot;canvasLocation&quot; x=&quot;13.6&quot; y=&quot;-5.8470764617691158&quot;/&gt;
          &lt;/view&gt;
      &lt;/objects&gt;
      &lt;designables&gt;
          &lt;designable name=&quot;E5w-YA-UY8&quot;&gt;
              &lt;size key=&quot;intrinsicContentSize&quot; width=&quot;77&quot; height=&quot;33&quot;/&gt;
          &lt;/designable&gt;
      &lt;/designables&gt;
      &lt;resources&gt;
          &lt;systemColor name=&quot;tertiarySystemBackgroundColor&quot;&gt;
              &lt;color white=&quot;1&quot; alpha=&quot;1&quot; colorSpace=&quot;custom&quot; customColorSpace=&quot;genericGamma22GrayColorSpace&quot;/&gt;
          &lt;/systemColor&gt;
      &lt;/resources&gt;
  &lt;/document&gt;
  </code></pre>
  <p>Any help with this would be greatly appreciated. Thanks.</p>