On this page14 sections
Lecture 004 — Banner Ads
| Category | 2 — Banner & Full-Screen Ads |
| Lecture | 004 of 010 |
| Estimated video length | 18 min |
| Target | Flutter 3.44 · Dart 3.12 · google_mobile_ads 9 |
| Level | Beginner |
| Source code | GitHub — urraan_admob_final |
A banner is the simplest ad: a strip that sits on screen while the user works. The one trick is to reserve its space before it loads, so the screen does not jump.
Contents
Prerequisites · Connection · Objectives · Lesson · Code Examples · Common Mistakes · Best Practices · Mini Challenge · Practice Questions · Answers · Takeaways
Prerequisites
Lectures 001–003; StatefulWidget, didChangeDependencies, bottomNavigationBar.
Connection With Previous Lectures
The SDK is initialised. The first ad we show is the banner, in the bottom bar of its own screen.
Learning Objectives
By the end of this lecture you will be able to:
- Create a
BannerAdand load it - Show it with
AdWidget - Reserve space so the layout does not jump
- Dispose the ad with the screen
Lesson
1. The Helper
// lib/admob/banner_ad_helper.dart
import 'package:flutter/material.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart';
import 'admob_manager.dart';
class BannerAdHelper {
BannerAd? _bannerAd;
bool isLoaded = false;
void loadBannerAd(
BuildContext context,
VoidCallback onAdLoaded, {
int height = 100,
}) {
_bannerAd?.dispose();
isLoaded = false;
_bannerAd = BannerAd(
size: AdSize(
width: MediaQuery.of(context).size.width.truncate(),
height: height,
),
adUnitId: AdmobManager.bannerAdaptiveId,
listener: BannerAdListener(
onAdLoaded: (_) {
isLoaded = true;
onAdLoaded();
},
onAdFailedToLoad: (ad, error) {
debugPrint('Banner failed: ${error.code} ${error.message}');
ad.dispose();
},
),
request: const AdRequest(),
)..load();
}
BannerAd? get bannerAd => isLoaded ? _bannerAd : null;
void dispose() => _bannerAd?.dispose();
/// Reserves the banner's height before it loads, so the layout never jumps.
static Widget getBannerView({
required bool isPurchase,
required bool isLoaded,
required BannerAd? bannerAd,
double height = 100,
}) {
if (isPurchase) return const SizedBox();
return Container(
color: Colors.grey.shade100,
padding: const EdgeInsets.symmetric(vertical: 5),
height: isLoaded && bannerAd != null
? bannerAd.size.height.toDouble()
: height,
width: double.infinity,
child: isLoaded && bannerAd != null
? AdWidget(ad: bannerAd)
: const SizedBox(),
);
}
}BannerAd(size:, adUnitId:, listener:, request:)— the ad object.AdSize(width:, height:)— full screen width and a height we choose.onAdLoadedsetsisLoadedand tells the screen to rebuild;onAdFailedToLoaddisposes the failed ad.getBannerViewreturns a fixed-height container even before the ad loads. That reserved space is why the content above does not move when the ad arrives.bannerAdreturnsnulluntil loaded, so a screen cannot show a half-ready ad.
2. The Screen
// lib/screen_banner_ads.dart
import 'package:flutter/material.dart';
import 'admob/banner_ad_helper.dart';
class ScreenBannerAds extends StatefulWidget {
const ScreenBannerAds({super.key});
@override
State<ScreenBannerAds> createState() => _ScreenBannerAdsState();
}
class _ScreenBannerAdsState extends State<ScreenBannerAds> {
final bannerAdHelper = BannerAdHelper();
// didChangeDependencies, not initState: loading needs MediaQuery (the screen width).
@override
void didChangeDependencies() {
super.didChangeDependencies();
bannerAdHelper.loadBannerAd(context, () {
if (mounted) setState(() {});
}, height: 200);
}
@override
void dispose() {
bannerAdHelper.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Banner Ads')),
bottomNavigationBar: BannerAdHelper.getBannerView(
isPurchase: false,
isLoaded: bannerAdHelper.isLoaded,
bannerAd: bannerAdHelper.bannerAd,
height: 200,
),
body: const Center(child: Text('Banner sits at the bottom')),
);
}
}didChangeDependenciesinstead ofinitStatebecause we needMediaQueryfor the width. That method can run more than once, so the helper disposes any previous ad before creating a new one.if (mounted) setState(...)— the ad may load after the screen is closed.disposereleases the ad's memory.
3. Adaptive Banners
A custom AdSize is fine for learning. For production, adaptive banners
(AdSize.getCurrentOrientationAnchoredAdaptiveBannerAdSize(width)) choose the best height for
the device and usually fill better.
Code Examples
Example 1 — Banner Height
Change height: 200 in both the helper call and getBannerView to 100. Run again: the
reserved area and the ad shrink together. Keep the two numbers equal.
Common Beginner Mistakes
1. Not disposing — leaks memory; call dispose in the screen.
2. setState after dispose — guard with mounted.
3. Different heights for reserve and ad — the screen jumps when the ad loads.
4. Placing a banner inside a scrolling list without a fixed height — it throws a layout error.
Best Practices
- Reserve the banner's height before it loads
- Put banners where they do not sit next to buttons — accidental taps are against policy
- One banner per screen is enough
Mini Challenge
Move the banner to the top using AppBar's bottom: or a Column at the top of the body.
Practice Questions
- Why
didChangeDependencieshere? - Why a fixed-height container?
- What does
bannerAdreturn before loading? - What should
disposedo?
Practice Answers
MediaQueryis needed for the width.- So the layout does not jump when the ad appears.
null.- Release the ad object.
Key Takeaways
- Banner =
BannerAd+AdWidget - Reserve the space; dispose the ad
- Prefer adaptive banners in production