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) } }
解决方案
问题根源
- 默认的BannerViewController会让容器视图撑满父容器,导致SwiftUI中BannerView占用过多空间
- 添加
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
相关产品推荐
相关产品推荐

