1
+ import 'dart:io' ;
2
+ import 'package:flutter/material.dart' ;
3
+ import 'package:collection/collection.dart' ;
4
+ import 'package:google_mobile_ads/google_mobile_ads.dart' ;
5
+
6
+ class MultiInlineAdaptiveWithRecycleExample extends StatefulWidget {
7
+ const MultiInlineAdaptiveWithRecycleExample ({super .key});
8
+
9
+ @override
10
+ State <StatefulWidget > createState () => _MultiInlineAdaptiveWithRecycleExampleState ();
11
+ }
12
+
13
+ class _MultiInlineAdaptiveWithRecycleExampleState extends State <MultiInlineAdaptiveWithRecycleExample > {
14
+
15
+ // A list of all the banners created.
16
+ final List <BannerAd > _banners = [];
17
+ // Keep track of sizes of the banners (since they can be different sizes).
18
+ final Map <BannerAd , AdSize > _bannerSizes = {};
19
+
20
+ // The maximum number of banners we create.
21
+ static const _cacheSize = 10 ;
22
+ // Keep track of the positions of banners.
23
+ final Map <BannerAd , int > _bannerPositions = {};
24
+
25
+ BannerAd _createBannerAd () {
26
+ final String bannerId = Platform .isAndroid
27
+ ? 'ca-app-pub-3940256099942544/6300978111'
28
+ : 'ca-app-pub-3940256099942544/2934735716' ;
29
+ AdSize adSize = AdSize .getCurrentOrientationInlineAdaptiveBannerAdSize (360 );
30
+ final BannerAd bannerAd = BannerAd (
31
+ adUnitId: bannerId,
32
+ request: const AdRequest (),
33
+ size: adSize,
34
+ listener: BannerAdListener (
35
+ onAdLoaded: (Ad ad) async {
36
+ BannerAd bannerAd = (ad as BannerAd );
37
+ final AdSize ? adSize = await bannerAd.getPlatformAdSize ();
38
+ // When the banner size is updated, we want to rebuild.
39
+ if (adSize != null && adSize != _bannerSizes[bannerAd]) {
40
+ setState (() {
41
+ _bannerSizes[bannerAd] = adSize;
42
+ });
43
+ }
44
+ },
45
+ ),
46
+ );
47
+ bannerAd.load ();
48
+ return bannerAd;
49
+ }
50
+
51
+ BannerAd _getRecycledBannerAd (int bannerPosition) {
52
+ // If we already created a banner for this position, just reuse it.
53
+ BannerAd ? bannerAd = _banners.firstWhereOrNull ((banner) => _bannerPositions[banner] == bannerPosition);
54
+ if (bannerAd != null ) {
55
+ return bannerAd;
56
+ }
57
+
58
+ // If the cache is not full, create a new banner
59
+ if (_banners.length < _cacheSize) {
60
+ BannerAd bannerAd = _createBannerAd ();
61
+ _banners.add (bannerAd);
62
+ _bannerPositions[bannerAd] = bannerPosition;
63
+ return bannerAd;
64
+ }
65
+
66
+ // Now the cache is full, we should recycle the banner (if possible).
67
+ BannerAd banner = _banners[bannerPosition % _cacheSize];
68
+ if (banner.isMounted) {
69
+ // Create a new banner if it's not possible to recycle the banner
70
+ // e.g. show 15 banners on screen, but _cacheSize is only 10.
71
+ return _createBannerAd ();
72
+ } else {
73
+ // Found a recyclable banner, mark it as being used by current banner position.
74
+ _bannerPositions[banner] = bannerPosition;
75
+ return banner;
76
+ }
77
+ }
78
+
79
+ @override
80
+ Widget build (BuildContext context) {
81
+ return Scaffold (
82
+ appBar: AppBar (title: Text ('Adaptive Size, Recycle' )),
83
+ body: ListView .builder (
84
+ // Arbitrary example of 1000 items in the list.
85
+ itemCount: 1000 ,
86
+ itemBuilder: (BuildContext context, int index) {
87
+ // We show a banner every 3 rows (i.e. row index 0, 3, 6, 9, 12, etc will be banner row)
88
+ if (index % 3 == 0 ) {
89
+ int bannerPosition = index ~ / 3 ;
90
+ BannerAd bannerAd = _getRecycledBannerAd (bannerPosition);
91
+ final AdSize ? adSize = _bannerSizes[bannerAd];
92
+ if (adSize == null ) {
93
+ // Null adSize means the banner's content is not fetched yet.
94
+ return SizedBox (height: 50 , child: Text ("banner is loading" ));
95
+ } else {
96
+ // Now this banner is loaded with ad content and corresponding ad size.
97
+ return SizedBox (width: adSize.width.toDouble (), height: adSize.height.toDouble (), child: AdWidget (ad: bannerAd));
98
+ }
99
+ } else {
100
+ // Show your regular non-ad content.
101
+ return SizedBox (height: 200 , child: ColoredBox (color: Colors .yellow));
102
+ }
103
+ }),
104
+ );
105
+ }
106
+ }
0 commit comments