You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI List视图Google横幅广告按需显示异常求助

解决SwiftUI List中广告加载失败时的空白问题

核心思路是给每个广告添加加载状态标记,根据状态控制广告视图的显示与隐藏,同时调整视图高度为0,避免List出现空白单元格。

修改后的完整代码

import SwiftUI

struct ContentView: View {
    let bannerId = "ca-app-pub-3940256099942544/2934735716"
    // 存储每个广告的加载状态,初始都为未加载
    @State private var adLoadedStates = Array(repeating: false, count: 10)
    
    var body: some View {
        ZStack {
            VStack(alignment: .center, spacing: 0) {
                navBar()
                    .background(Color.blue)
                List(0..<10) { index in
                    // 仅当广告加载成功时才显示广告单元格
                    if adLoadedStates[index] {
                        HStack {
                            Spacer()
                            AdBannerView(
                                bannerID: bannerId,
                                adWidth: 320,
                                adHeight: 50,
                                isAdLoaded: $adLoadedStates[index]
                            )
                            Spacer()
                        }
                    }
                    Text("Hello world!")
                }
                .listStyle(.plain)
                Spacer()
            }
        }
    }
    
    // 自定义导航栏示例(可替换为你的实际实现)
    func navBar() -> some View {
        Text("导航栏")
            .foregroundColor(.white)
            .padding()
    }
}

import UIKit
import GoogleMobileAds

struct AdBannerView: UIViewControllerRepresentable {
    var bannerID: String
    var adWidth: CGFloat
    var adHeight: CGFloat
    // 绑定广告加载状态,用于通知父视图更新
    @Binding var isAdLoaded: Bool

    func makeCoordinator() -> Coordinator { Coordinator(self) }

    func makeUIViewController(context: Context) -> UIViewController {
        print("makeUIViewController called")
        let bannerView = GADBannerView(frame: CGRect(x: 0, y: 0, width: adWidth, height: adHeight))
        let viewController = UIViewController()
        bannerView.adUnitID = bannerID
        bannerView.rootViewController = viewController
        viewController.view.addSubview(bannerView)
        bannerView.load(GADRequest())
        bannerView.delegate = context.coordinator
        // 初始状态设为未加载
        isAdLoaded = false
        return viewController
    }
    
    @available(iOS 16.0, *)
    func sizeThatFits(_ proposal: ProposedViewSize, uiViewController: UIViewController, context: Context) -> CGSize? {
        // 根据加载状态返回高度,未加载则高度为0
        isAdLoaded ? CGSize(width: adWidth, height: adHeight) : .zero
    }

    func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
        print("updateUIViewController called")
        // 同步隐藏/显示广告视图
        if let bannerView = uiViewController.view.subviews.first as? GADBannerView {
            bannerView.isHidden = !isAdLoaded
        }
    }
    
    class Coordinator : NSObject, GADBannerViewDelegate {
        var parent : AdBannerView
        init(_ parent : AdBannerView) { self.parent = parent }
        
        public func bannerViewDidReceiveAd(_ bannerView: GADBannerView) {
            print("Ads received successfully")
            // 标记广告加载成功,触发父视图刷新
            parent.isAdLoaded = true
        }
        
        public func bannerView(_ bannerView: GADBannerView, didFailToReceiveAdWithError error: Error) {
            print("Ad loads to fail: \(error.localizedDescription)")
            // 标记广告加载失败,触发父视图刷新
            parent.isAdLoaded = false
        }
    }
}

关键修改点

  1. 添加加载状态数组:在ContentView中用@State private var adLoadedStates存储每个广告的加载状态,确保每个广告单元格独立控制显示逻辑。
  2. 绑定状态到AdBannerView:给AdBannerView添加@Binding var isAdLoaded,让子视图能将广告加载结果同步给父视图。
  3. 根据状态控制显示:
    • 在List中仅当对应广告的加载状态为true时,才渲染广告单元格。
    • 在AdBannerView的sizeThatFits方法中,未加载成功时返回高度为0,彻底消除空白占位。
    • 在updateUIViewController中同步隐藏广告视图,确保视觉上完全不显示未加载的广告。
  4. 代理方法更新状态:在Coordinator的广告加载成功/失败回调中,更新isAdLoaded的状态值,触发SwiftUI视图自动刷新。

内容的提问来源于stack exchange,提问作者Karthik Kurdekar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 18:07:43