Implementing Ads in Apps with Page Transitions
This post is a continuation of this article.
You've hit on a good point.
The biggest source of accidents with ads is how to make them coexist with page transitions.
If you nail this in your design, it will immediately look professional.
I'll start with the conclusion.
Ads should be attached to "transition events," not "screen components."
Hardcoding them inside pages will lead to failure.
First, the major premise (this is super important).
In Flutter, page transitions are essentially this:
Navigator.push → stacking a screen onto the stack
Navigator.pop → removing a screen from the stack
Ads, especially full-screen ads (Interstitial / Rewarded) are
not "screens" but interruptive events.
Therefore, separate the design like this:
Screen UI → Widget tree
Ads → Processes that fire before or after transitions
The correct placement for each type of ad
Banner ads
This is simple.
The bottomNavigationBar of each page's Scaffold
Or just once in a common layout
👉 They switch together even when the page transitions
Scaffold(
body: ...
bottomNavigationBar: const BannerAdWidget(),
);
Interstitial ads (the main one)
This is right before or right after a page transition.
❌ NG Example
onPressed: () {
_showInterstitialAd();
Navigator.push(...);
}
This is prone to breaking due to timing conflicts.
Correct Pattern 1: Show ads before transition
The "take a breath before moving to the next screen" pattern.
onPressed: () async {
await AdService.instance.showInterstitialIfReady();
Navigator.push(
context,
MaterialPageRoute(builder: (_) => NextPage()),
);
}
Why is this good?
Ads won't overlap after the transition finishes
UI is less likely to break
Stable even on iOS
Correct Pattern 2: Show ads after transition
The "show after the screen has switched" pattern.
Navigator.push(
context,
MaterialPageRoute(builder: (_) => NextPage()),
).then((_) {
AdService.instance.showInterstitialIfReady();
});
Use cases
List → Detail
Settings → Back
Isolate ad logic into a "Service"
This is the core of the design.
❌ Write ad code for each screen
⭕ Create one dedicated ad class
AdService (example)
class AdService {
AdService._();
static final instance = AdService._();
InterstitialAd? _interstitialAd;
void loadInterstitial() {
InterstitialAd.load(
adUnitId: InterstitialAd.testAdUnitId,
request: const AdRequest(),
adLoadCallback: InterstitialAdLoadCallback(
onAdLoaded: (ad) {
_interstitialAd = ad;
},
onAdFailedToLoad: (_) {
_interstitialAd = null;
},
),
);
}
Future<void> showInterstitialIfReady() async {
if (_interstitialAd == null) return;
final completer = Completer<void>();
_interstitialAd!.fullScreenContentCallback =
FullScreenContentCallback(
onAdDismissedFullScreenContent: (ad) {
ad.dispose();
_interstitialAd = null;
loadInterstitial();
completer.complete();
},
onAdFailedToShowFullScreenContent: (ad, _) {
ad.dispose();
_interstitialAd = null;
loadInterstitial();
completer.complete();
},
);
_interstitialAd!.show();
_interstitialAd = null;
return completer.future;
}
}
Breaking down the key points
Manage only one ad at a time
Dispose of it once displayed
Preload for the next one
The screen side just says 'show if possible'
What to do at app startup
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await MobileAds.instance.initialize();
AdService.instance.loadInterstitial();
runApp(MyApp());
}
👉
The page doesn't know about the ad
The ad doesn't know about the page structure
This is healthy.
A design that works better the more page transitions an app has
Like your app:
List → Detail
Tab switching
Frequent back operations
In this kind of structure,
Placing ads as Widgets
→ Will failLinking ads to transition events
→ Will be stable
One last word (the core of the design)
Ads are not UI. They are events.
If you can grasp this concept,
it won't break even if pages increase or transitions become complex.
The next common sticking point is
'Should I show an ad when the back button (pop) is pressed?'
Setting a rule for this will also clear things up immediately.
