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

SwiftUI中AdMob自适应横幅显示异常问题求助

SwiftUI集成AdMob自适应横幅广告的布局问题解决

问题场景

我按照官方文档在SwiftUI中集成AdMob自适应横幅广告,应用内包含一个简单TabView,子页面用VStack布局,包含Text组件和BannerView,代码如下:

var body: some View {
    VStack {
        Text("Foo")
        Spacer()
        BannerView()
    }
}

当前遇到两个问题:

  • BannerView会占满VStack剩余的全部空间
  • 给BannerView添加.fixedSize(horizontal: false, vertical: true)修饰符后,广告会被TabView遮挡,显示在后方

BannerView及BannerViewController的代码完全遵循官方文档:

struct BannerView: UIViewControllerRepresentable {

static let shared: BannerView = BannerView()

@State
private var viewWidth: CGFloat = .zero

private let bannerView = GADBannerView()
private let adUnitID = "ca-app-pub-3940256099942544/2934735716"

func makeUIViewController(context: Context) -> some UIViewController {
    let bannerViewController = BannerViewController()
    bannerView.adUnitID = adUnitID
    bannerView.rootViewController = bannerViewController
    bannerViewController.view.addSubview(bannerView)
    bannerViewController.delegate = context.coordinator
    
    return bannerViewController
}

func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {
    guard viewWidth != .zero else { return }
    
    bannerView.adSize = GADCurrentOrientationAnchoredAdaptiveBannerAdSizeWithWidth(viewWidth)
    bannerView.load(GADRequest())
}

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

class Coordinator: NSObject, BannerViewControllerWidthDelegate {
    let parent: BannerView
    
    init(_ parent: BannerView) {
        self.parent = parent
    }
    
    func bannerViewController(_ bannerViewController: BannerViewController, didUpdate width: CGFloat) {
        parent.viewWidth = width
    }
}
}

BannerViewController代码:

protocol BannerViewControllerWidthDelegate: AnyObject {
    func bannerViewController(_ bannerViewController: BannerViewController, didUpdate width: CGFloat)
}

class BannerViewController: UIViewController {
    weak var delegate: BannerViewControllerWidthDelegate?

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
    
        delegate?.bannerViewController(self, didUpdate: view.frame.inset(by: view.safeAreaInsets).size.width)
    }    
}

解决方案

问题根源

  1. 默认的BannerViewController会让容器视图撑满父容器,导致SwiftUI中BannerView占用过多空间
  2. 添加fixedSize后广告被遮挡,是因为BannerViewController未正确处理安全区域和TabBar的层级关系

修复步骤

1. 修改BannerViewController,实现自适应尺寸

更新BannerViewController代码,添加自动布局约束,让容器视图跟随BannerView的大小,同时修正初始化逻辑:

protocol BannerViewControllerWidthDelegate: AnyObject {
    func bannerViewController(_ bannerViewController: BannerViewController, didUpdate width: CGFloat)
}

class BannerViewController: UIViewController {
    weak var delegate: BannerViewControllerWidthDelegate?
    private let bannerView: GADBannerView
    
    // 新增:通过初始化传递BannerView
    init(bannerView: GADBannerView) {
        self.bannerView = bannerView
        super.init(nibName: nil, bundle: nil)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.addSubview(bannerView)
        
        // 添加自动布局约束,让BannerView撑满容器视图
        bannerView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            bannerView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            bannerView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            bannerView.topAnchor.constraint(equalTo: view.topAnchor),
            bannerView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
        ])
        
        // 让容器视图自适应内容尺寸,不强制撑满父容器
        view.sizeToFit()
    }
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        let safeWidth = view.frame.inset(by: view.safeAreaInsets).size.width
        delegate?.bannerViewController(self, didUpdate: safeWidth)
    }
}

2. 调整BannerView的实现逻辑

修改makeUIViewController方法,将bannerView传入BannerViewController的初始化:

struct BannerView: UIViewControllerRepresentable {
    static let shared: BannerView = BannerView()
    
    @State private var viewWidth: CGFloat = .zero
    private let bannerView = GADBannerView()
    private let adUnitID = "ca-app-pub-3940256099942544/2934735716"
    
    func makeUIViewController(context: Context) -> some UIViewController {
        bannerView.adUnitID = adUnitID
        // 传入bannerView初始化BannerViewController
        let bannerViewController = BannerViewController(bannerView: bannerView)
        bannerView.rootViewController = bannerViewController
        bannerViewController.delegate = context.coordinator
        return bannerViewController
    }
    
    func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {
        guard viewWidth != .zero else { return }
        bannerView.adSize = GADCurrentOrientationAnchoredAdaptiveBannerAdSizeWithWidth(viewWidth)
        bannerView.load(GADRequest())
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
    
    class Coordinator: NSObject, BannerViewControllerWidthDelegate {
        let parent: BannerView
        
        init(_ parent: BannerView) {
            self.parent = parent
        }
        
        func bannerViewController(_ bannerViewController: BannerViewController, didUpdate width: CGFloat) {
            parent.viewWidth = width
        }
    }
}

3. 优化SwiftUI页面布局

移除fixedSize修饰符,添加安全区域忽略设置,确保广告显示在TabView上方:

var body: some View {
    VStack {
        Text("Foo")
        Spacer()
        BannerView()
            .ignoresSafeArea(edges: .bottom) // 让广告紧贴屏幕底部,不被安全区域留白
    }
}

效果验证

修改完成后:

  • BannerView会自动适配广告的实际高度,不再占满剩余空间
  • 广告将正确显示在TabView上方,不会被遮挡

内容的提问来源于stack exchange,提问作者Javier Cancio

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 15:39:23