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

Flutter:如何在应用所有页面底部固定一个容器

实现跨页面固定底部AdMob广告的方案

核心思路是将广告组件放在全局父容器中,而非每个页面单独嵌入,这样页面切换时广告不会被销毁重建。以下分平台给出具体实现:

Android 实现

1. 传统View系统(XML布局)

用主Activity作为全局容器,底部固定广告View,上方用Fragment容器承载页面内容:

  • 主布局activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:ads="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <!-- 页面内容容器 -->
    <FrameLayout
        android:id="@+id/fragment_container"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />

    <!-- 底部固定广告 -->
    <com.google.android.gms.ads.AdView
        android:id="@+id/adView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        ads:adSize="BANNER"
        ads:adUnitId="@string/ad_unit_id" />
</LinearLayout>
  • 主Activity逻辑:
class MainActivity : AppCompatActivity() {
    private lateinit var adView: AdView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // 初始化广告
        adView = findViewById(R.id.adView)
        val adRequest = AdRequest.Builder().build()
        adView.loadAd(adRequest)

        // 加载初始页面
        supportFragmentManager.beginTransaction()
            .replace(R.id.fragment_container, HomeFragment())
            .commit()
    }

    // 页面切换仅替换Fragment
    fun switchPage(fragment: Fragment) {
        supportFragmentManager.beginTransaction()
            .replace(R.id.fragment_container, fragment)
            .addToBackStack(null)
            .commit()
    }
}

2. Jetpack Compose

利用Scaffold的bottomBar参数固定广告,通过Navigation组件切换页面:

@Composable
fun MainScreen(navController: NavHostController) {
    Scaffold(
        bottomBar = { AdBanner() }
    ) { paddingValues ->
        NavHost(
            navController = navController,
            startDestination = "home",
            modifier = Modifier.padding(paddingValues)
        ) {
            composable("home") { HomeScreen(navController) }
            composable("profile") { ProfileScreen(navController) }
            // 其他页面路由
        }
    }
}

@Composable
fun AdBanner() {
    AndroidView(
        factory = { context ->
            AdView(context).apply {
                adSize = AdSize.BANNER
                adUnitId = context.getString(R.string.ad_unit_id)
                loadAd(AdRequest.Builder().build())
            }
        },
        modifier = Modifier.fillMaxWidth()
    )
}

iOS 实现

1. UIKit

自定义导航控制器,将广告View添加到容器底部:

class BaseNavigationController: UINavigationController {
    private let adView = GADBannerView(adSize: GADAdSizeBanner)

    override func viewDidLoad() {
        super.viewDidLoad()

        // 配置广告
        adView.adUnitID = "你的广告单元ID"
        adView.rootViewController = self
        adView.load(GADRequest())

        // 固定到容器底部
        view.addSubview(adView)
        adView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            adView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
            adView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            adView.trailingAnchor.constraint(equalTo: view.trailingAnchor)
        ])

        // 避免内容被广告遮挡
        viewControllers.first?.view.bottomAnchor.constraint(equalTo: adView.topAnchor).isActive = true
    }
}

所有页面通过该导航控制器跳转,广告始终保留。

2. SwiftUI

用NavigationStack结合Toolbar的bottomBar固定广告:

struct MainView: View {
    @State private var path = NavigationPath()

    var body: some View {
        NavigationStack(path: $path) {
            HomeView(path: $path)
                .navigationDestination(for: Page.self) { page in
                    switch page {
                    case .profile: ProfileView(path: $path)
                    case .settings: SettingsView(path: $path)
                    }
                }
                .toolbar {
                    ToolbarItem(placement: .bottomBar) {
                        AdBannerView()
                    }
                }
        }
    }
}

struct AdBannerView: UIViewRepresentable {
    func makeUIView(context: Context) -> GADBannerView {
        let bannerView = GADBannerView(adSize: GADAdSizeBanner)
        bannerView.adUnitID = "你的广告单元ID"
        bannerView.rootViewController = UIApplication.shared.windows.first?.rootViewController
        bannerView.load(GADRequest())
        return bannerView
    }

    func updateUIView(_ uiView: GADBannerView, context: Context) {}
}

enum Page: Hashable {
    case profile, settings
}

通用注意事项

  • 测试阶段使用AdMob官方测试ID,避免违规:
    • Android测试ID:ca-app-pub-3940256099942544/6300978111
    • iOS测试ID:ca-app-pub-3940256099942544/2934735716
  • 遵守AdMob政策,不要遮挡广告或频繁触发广告请求
  • 跨平台框架(Flutter/React Native)思路一致:将广告放在全局根组件底部,页面内容放在上方导航容器中

内容的提问来源于stack exchange,提问作者Mhmd Khatib

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 19:27:16