SwiftUI中Ad Mob横幅广告加载失败时如何隐藏以不占屏幕空间?
解决SwiftUI横幅广告加载失败时不占用空间的问题
你遇到的核心问题是:仅隐藏BannerView无法让外层SwiftUI视图释放空间,因为SwiftUI层不知道广告加载失败的状态。需要把UIKit层的广告加载状态传递到SwiftUI层,让视图根据状态动态调整布局。
以下是具体修改步骤:
1. 给BannerAdVC添加加载状态绑定
在UIKit控制器中新增绑定属性,用于通知SwiftUI广告的加载状态:
class BannerAdVC: UIViewController, GADBannerViewDelegate { let adUnitId: String @Binding var isAdLoaded: Bool // 新增绑定属性 init(adUnitId: String, isAdLoaded: Binding<Bool>) { self.adUnitId = adUnitId self._isAdLoaded = isAdLoaded super.init(nibName: nil, bundle: nil) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } var bannerView: GADBannerView = GADBannerView() override func viewDidLoad() { bannerView.delegate = self bannerView.adUnitID = adUnitId bannerView.rootViewController = self view.addSubview(bannerView) } // ... 原有viewDidAppear、viewWillTransition、loadBannerAd代码保持不变 }
2. 实现广告加载状态的代理方法
补充GADBannerViewDelegate的关键方法,更新加载状态并处理BannerView显示:
// 广告加载成功时触发 func bannerViewDidReceiveAd(_ bannerView: GADBannerView) { isAdLoaded = true bannerView.isHidden = false } // 广告加载失败时触发 func bannerView(_ bannerView: GADBannerView, didFailToReceiveAdWithError error: Error) { print("Failed to receive ad: \(error.localizedDescription)") isAdLoaded = false bannerView.isHidden = true bannerView.backgroundColor = .clear }
3. 修改BannerAd组件传递状态
更新UIViewControllerRepresentable组件,添加绑定属性并传递给控制器:
struct BannerAd: UIViewControllerRepresentable { let adUnitId: String @Binding var isAdLoaded: Bool // 新增绑定属性 init(adUnitId: String, isAdLoaded: Binding<Bool>) { self.adUnitId = adUnitId self._isAdLoaded = isAdLoaded } func makeUIViewController(context: Context) -> BannerAdVC { return BannerAdVC(adUnitId: adUnitId, isAdLoaded: $isAdLoaded) } func updateUIViewController(_ uiViewController: BannerAdVC, context: Context) { // 可根据需求添加视图更新逻辑 } }
4. 调整SwiftUIBannerAd的布局逻辑
在SwiftUI视图中添加加载状态变量,根据状态动态显示广告或空视图:
public struct SwiftUIBannerAd: View { @State var height: CGFloat = 0 @State var width: CGFloat = 0 @State var adPosition: AdPosition let adUnitId: String @State private var isAdLoaded = false // 新增加载状态变量 public init(adPosition: AdPosition, adUnitId: String) { self.adPosition = adPosition self.adUnitId = adUnitId } public enum AdPosition { case top case bottom } public var body: some View { VStack { if adPosition == .bottom { Spacer() } // 根据加载状态切换显示内容 if isAdLoaded { BannerAd(adUnitId: adUnitId, isAdLoaded: $isAdLoaded) .frame(width: width, height: height, alignment: .center) } else { EmptyView() .frame(height: 0) // 失败时高度设为0,不占用空间 } if adPosition == .top { Spacer() } } .onAppear { setFrame() } .onReceive(NotificationCenter.default.publisher(for: UIDevice.orientationDidChangeNotification)) { _ in setFrame() } } func setFrame() { let safeAreaInsets = UIApplication.shared.windows.first(where: { $0.isKeyWindow })?.safeAreaInsets ?? .zero let frame = UIScreen.main.bounds.inset(by: safeAreaInsets) let adSize = GADCurrentOrientationAnchoredAdaptiveBannerAdSizeWithWidth(frame.width) self.width = adSize.size.width self.height = adSize.size.height } }
5. 优化外部调用代码(可选)
现在SwiftUIBannerAd会自动处理加载失败的隐藏逻辑,外部调用可以简化:
HStack { Spacer() SwiftUIBannerAd(adPosition: .top, adUnitId: StaticCodes.bannerCode) .padding() Spacer() }
修改完成后,广告加载失败时,SwiftUI会显示高度为0的空视图,完全不占用屏幕空间;加载成功则正常展示横幅广告。
内容的提问来源于stack exchange,提问作者RinaredStaring
相关产品推荐
相关产品推荐

