How to hide banner ad when navigating to next page in flutter? - flutter

I am setting ads in flutter app using firebase_admob plugin. I tried banner ad and it is working fine but, when i navigate to another page it still remains at its position. I want that ad should hide when navigating to another page.
The code snippet is as follows.
BannerAd myBanner = BannerAd(
// Replace the testAdUnitId with an ad unit id from the AdMob dash.
// https://developers.google.com/admob/android/test-ads
// https://developers.google.com/admob/ios/test-ads
adUnitId: BannerAd.testAdUnitId,
size: AdSize.smartBanner,
targetingInfo: targetingInfo,
listener: (MobileAdEvent event) {
print("BannerAd event is $event");
},
);
myBanner
// typically this happens well before the ad is shown
..load()
..show(
// Positions the banner ad 60 pixels from the bottom of the screen
anchorOffset: 60.0,
// Banner Position
anchorType: AnchorType.bottom,
);

You can use RouteObserver:
class AdmobObserver extends RouteObserver<PageRoute<dynamic>> {
BannerAd _myBanner = BannerAd(
adUnitId: BannerAd.testAdUnitId,
size: AdSize.smartBanner,
listener: (MobileAdEvent event) {
print("BannerAd event is $event");
},
);
#override
void didPush(Route route, Route previousRoute) {
super.didPush(route, previousRoute);
if (route.settings.name == '/') {
// show the banner when navigating to home screen
_showBannerAd();
} else {
// hide the banner when navigating to another screen
_myBanner.dispose();
}
}
#override
void didPop(Route route, Route previousRoute) {
super.didPop(route, previousRoute);
if (previousRoute.settings.name == '/') {
// show the banner again when returning back to the home screen
_showBannerAd();
}
}
void _showBannerAd() {
_myBanner
..load()
..show(
anchorOffset: 60.0,
// Banner Position
anchorType: AnchorType.bottom,
);
}
}
Then you need to add this observer to your MaterialApp:
static AdmobObserver admobObserver = AdmobObserver();
#override
Widget build(BuildContext context) {
return MaterialApp(
navigatorObservers: <NavigatorObserver>[admobObserver],
.
.
.

dispose() will be called when a page is destroyed. So you can distroy banner ad there.
#override
void dispose() {
myBanner.dispose();
super.dispose();
}

if you want to hide when show new Screen and re show when user return to last screen, you need to dispose before start new page and use async and await to await until new page pop from navigator, lets show some code
BannerAd bannerAd;
#override
void initState() {
super.initState();
initAds();
}
void openNewPage() async{
//hide banner before start new page
bannerAd?.dispose();
await Navigator.push(context, MaterialPageRoute(builder: (_) => MySecondScreen()));
//now user is return to this page so reshow banner
initAds();
}
#override
void dispose() {
super.dispose();
bannerAd?.dispose();
interstitialAd?.dispose();
}
void initAds() async {
bannerAd = BannerAd(
adUnitId: kReleaseMode ? Constant.BANNER_AD_ID : BannerAd.testAdUnitId,
size: AdSize.smartBanner,
listener: (MobileAdEvent event) {
print("BannerAd event is $event");
},
);
bannerAd
// typically this happens well before the ad is shown
..load()
..show(
anchorType: AnchorType.bottom,
);
}
so inside this method we hide/reshow banner
void openNewPage() async{
//hide banner before start new page
bannerAd?.dispose();
await Navigator.push(context, MaterialPageRoute(builder: (_) => MySecondScreen()));
//now user is return to this page so reshow banner
initAds();
}

call Navigator.pop();
before calling Navigator.push() . This will solve your problem

Follow these steps.
Consider two pages/screens as HomePage and SecondPage.
Step 1. Add this code in HomePage to go to SecondPage
myBanner?.dispose();
myBanner = null;
Navigator.push(context,
MaterialPageRoute(builder: (context) => SecondPage()));
this will remove BannerAd object and banner will be disappeared.
Step 2. Add this code in SecondPage
Timer(Duration(seconds: 3), () {
if(secondPageBanner == null){
initState();
}
});
Put your BannerAd initialization/ Declaration code into initState() function.
This will show Banner in SecondPage.
Step 3. Add this code in SecondPage when back to Homepage
secondPageBanner?.dispose();
if(secondPageBanner != null){
secondPageBanner = null;
}
setState(() {
Navigator.pop(context);
});
This will make secondPageBanner hidden.
Step 4. Add this code in Homepage
Timer(Duration(seconds: 3), () {
if(myBanner == null){
initState();
}
});
OR like this
void function(){
if(myBanner == null){
initState();
}
}
in a button click function that button is normally clicked by user.
This will show myBanner Ad again in HomePage.

Related

How to open another page after rewarded ad is watched in Flutter?

Flutter App.
One button that leads to the 2nd page where the content is.
The user clicks on the button and must watch a video ad(rewarded ad).
After the video ad finishes > the user can open the 2nd page / or the 2nd page will be automatically opened when he clicks 'x' on the finished video ad.
My question is > how to do this? What would the code look like and what to use?
Thank you!
Use the following code on your first page above the build method
late RewardedAd _rewardedAd;
bool _isRewardedAdReady = false;
// TODO: Implement _loadRewardedAd()
void _loadRewardedAd() {
RewardedAd.load(
adUnitId: AdHelper.rewardedAdUnitId,
request: AdRequest(),
rewardedAdLoadCallback: RewardedAdLoadCallback(
onAdLoaded: (ad) {
this._rewardedAd = ad;
ad.fullScreenContentCallback = FullScreenContentCallback(
onAdDismissedFullScreenContent: (ad) {
setState(() {
_isRewardedAdReady = false;
});
_loadRewardedAd();
},
);
setState(() {
_isRewardedAdReady = true;
});
},
onAdFailedToLoad: (err) {
print('Failed to load a rewarded ad: ${err.message}');
setState(() {
_isRewardedAdReady = false;
});
},
),
);
}
After that initialize and dispose the rewardedad like
#override
void initState() {
_loadRewardedAd();
super.initState();
}
#override
void dispose() {
_rewardedAd.dispose();
super.dispose();
}
Now call the rewarede ad with Navigating to othe page
GestureDetector(
onTap: () {
if(_isRewardedAdReady){
_rewardedAd.show(onUserEarnedReward:
(RewardedAd ad, RewardItem reward) {
print(
'$ad with reward $RewardItem(${reward.amount}, ${reward.type}');
});
}
Navigator.pushReplacement(
context, MaterialPageRoute(builder: (context)=>SecondPage()));
},
child: CustomButton(text:'GoTo Second Page')
),
for better understand go to here

Go back to login when logged out from the drawer, no matter what

I need to redirect user to login page when he clicks on logout button from drawer (wherever he is). The problem is that when I click on the logout button, the screen remains the same.
According to this post: Flutter provider state management, logout concept
I have:
void main() async {
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider<Profile>(
create: (final BuildContext context) {
return Profile();
},
)
],
child: MyApp(),
),
);
}
MyApp:
class _MyAppState extends State<MyApp> {
#override
void initState() {
super.initState();
initPlatformState();
}
/// Platform messages are asynchronous, so we initialize in an async method.
Future<void> initPlatformState() async {
if (!mounted) return;
}
#override
Widget build(BuildContext context) {
return new MaterialApp(
initialRoute: '/',
navigatorKey: navigatorKey,
// ...
home: Consumer<Profile>(
builder: (context, profile, child){
return profile.isAuthenticated ? SplashScreen() : AuthScreen();
}
)
);
}
}
The part of the drawer where there is the logout button:
ListTile(
leading: Icon(Icons.logout),
title: Text(AppLocalizations.of(context)!.logout),
onTap: () async {
SharedPreferences preferences =
await SharedPreferences.getInstance();
await preferences.clear();
final Profile profile =
Provider.of<Profile>(context, listen: false);
profile.isAuthenticated = false;
}),
As I said, when I click on the logout button from the drawer, the user is correctly logged out, but the screen remains the same.
UPDATE
This is the profile class:
class Profile with ChangeNotifier {
bool _isAuthenticated = false;
bool get isAuthenticated {
return this._isAuthenticated;
}
set isAuthenticated(bool newVal) {
this._isAuthenticated = newVal;
this.notifyListeners();
}
}
I think you are using provider class incorrectly.
use your profile class like this.
class Profile with ChangeNotifier {
bool _isAuthenticated = true;
bool get getIsAuthenticated => _isAuthenticated;
set setIsAuthenticated(bool isAuthenticated) {
_isAuthenticated = isAuthenticated;
notifyListeners();//you must call this method to inform lisners
}
}
in set method call notifyListners();
in your listTile
replace profile.isAuthenticated = false to profile.isAuthenticated = false;
Always use getters and setters for best practice.
I hope this is what you were looking for.
Add Navigator.of(context).pushReplacementNamed("/routeName") in LogOut onTap() Section.
For more information : https://api.flutter.dev/flutter/widgets/Navigator/pushReplacementNamed.html
Make sure to have logout route set in MyApp file, and i'd edit logout button file as such:
ListTile(
leading: Icon(Icons.logout),
title: Text(AppLocalizations.of(context)!.logout),
onTap: () async {
SharedPreferences preferences =
await SharedPreferences.getInstance();
await preferences.clear();
final Profile profile =
Provider.of<Profile>(context, listen: false);
profile.isAuthenticated = false;
// add login file route here using Navigator.pushReplacementNamed() ;
}),
Navigator push named -> logout route?

pushing new page when state changes is causing weird behaviour

im new to flutter. I am trying to push to a new page whenever my qrcode reader detects a qrcode. however upon detecting the qrcode, infinite pages are being pushed. Can anyone provide me with some advice or sample code that pushes to a new page whenever the state changes?
class _QRViewExampleState extends State<QRViewExample> {
final GlobalKey qrKey = GlobalKey(debugLabel: 'QR');
_QRViewExampleState({this.state});
var state = false;
QRViewController controller;
#override
Widget build(BuildContext context) {
if (state == true) {
WidgetsBinding.instance.addPostFrameCallback((_) {
Navigator.of(context).push(
MaterialPageRoute(builder: (ctx) => Menu()),
);
// Navigation
});
}
return Scaffold(
...
);
}
void _onQRViewCreated(QRViewController controller) {
this.controller = controller;
controller.scannedDataStream.listen((scanData) {
setState(() {
state = true;
});
});
}
first of all, this line of code:
WidgetsBinding.instance.addPostFrameCallback((_) {});
usually used when you want run statement after build finished, and called inside initState(). in your case i think you don't need it.
i recommend you to call navigator inside your QRViewController listener:
_onQRViewCreated(QRViewController controller) {
this.controller = controller;
controller.scannedDataStream.listen((scanData) {
Navigator.of(context).push(
MaterialPageRoute(builder: (ctx) => Menu(scanData)),
);
});
}

How to change current page when app is inactive?

I need to redirect user to auth page when app is inactive for 5 minutes. I suppose using WidgetsBindingObserver. I detect when app is inactive for 5 minutes, but i don't know how to redirect user to auth page.
Here's part of my code:
#override
void initState() {
super.initState();
homeScreen = widget.homeScreen;
WidgetsBinding.instance.addObserver(this);
}
#override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
#override
void didChangeAppLifecycleState(AppLifecycleState state) {
setState(() {
if (state == AppLifecycleState.paused) {
Future.delayed(Duration(seconds: 3), () {
setState(() {
// navigate to auth page
});
});
}
});
}
You can use the Navigator:
Navigator.push(context,
MaterialPageRoute(builder: (context) => AuthPage()));
You don't need redirect an app in 5 minutes, you can redirect it when user want to navigate into page (or to do some action) which needed to be authenticated, just log last action timestamp into SharedPreferences and check this timestamp on every needed-auth action.

Android onResume() method equivalent in Flutter

I am working on a Flutter app and need to pop the screen. I tried initState() method but no luck. initState() gets called when I open a class for the first time.
Do we have an equivalent of Android onResume() method in Flutter?
Any ideas?
You can use the WidgetsBindingObserver and check the AppLifeCycleState like this example:
class YourWidgetState extends State<YourWidget> with WidgetsBindingObserver {
#override
void initState() {
WidgetsBinding.instance?.addObserver(this);
super.initState();
}
#override
void dispose() {
WidgetsBinding.instance?.removeObserver(this);
super.dispose();
}
#override
void didChangeAppLifecycleState(AppLifecycleState state) {
if (state == AppLifecycleState.resumed) {
//do your stuff
}
}
}
Take in mind that It will called every time you open the app or go the background and return to the app. (if your widget is active)
If you just want a listener when your Widget is loaded for first time, you can listen using addPostFrameCallback, like this example:
class YourWidgetState extends State<YourWidget> {
_onLayoutDone(_) {
//do your stuff
}
#override
void initState() {
WidgetsBinding.instance?.addPostFrameCallback(_onLayoutDone);
super.initState();
}
}
Info : https://docs.flutter.io/flutter/widgets/WidgetsBindingObserver-class.html
Update: Null safety compliance
If you go to another page, then is called when you comeback
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SecondPage(),
),
).then((value) {
_refreshFirstPage();
});
You can accomplish this by registering a didChangeAppLifecycleState observer:
class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
#override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}
#override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
#override
void didChangeAppLifecycleState(final AppLifecycleState state) {
if (state == AppLifecycleState.resumed) {
setState(() {
// ...your code goes here...
});
}
}
#override
Widget build(final BuildContext context) {
// ...your code goes here...
}
}
See WidgetsBindingObserver for more information.
Use focus_detector more information can see visibility_detector
Get notified every time your widget appears or disappears from the screen.
Similar to onResume()/onPause() on Android and viewDidAppear()/viewDidDisappear() on iOS.
Focus Detector fires callbacks for you whenever something happens to take or give your widget focus. Such an event might be, for instance, the user:
Navigating to/from another screen;
Turning the device’s screen on/off while your widget is visible;
Switching to/from another app while your widget is visible;
Scrolling your widget in/out the screen;
#override
Widget build(BuildContext context) =>
FocusDetector(
onFocusLost: () {
logger.i(
'Focus Lost.'
'\nTriggered when either [onVisibilityLost] or [onForegroundLost] '
'is called.'
'\nEquivalent to onPause() on Android or viewDidDisappear() on iOS.',
);
},
onFocusGained: () {
logger.i(
'Focus Gained.'
'\nTriggered when either [onVisibilityGained] or [onForegroundGained] '
'is called.'
'\nEquivalent to onResume() on Android or viewDidAppear() on iOS.',
);
},
onVisibilityLost: () {
logger.i(
'Visibility Lost.'
'\nIt means the widget is no longer visible within your app.',
);
},
onVisibilityGained: () {
logger.i(
'Visibility Gained.'
'\nIt means the widget is now visible within your app.',
);
},
onForegroundLost: () {
logger.i(
'Foreground Lost.'
'\nIt means, for example, that the user sent your app to the background by opening '
'another app or turned off the device\'s screen while your '
'widget was visible.',
);
},
onForegroundGained: () {
logger.i(
'Foreground Gained.'
'\nIt means, for example, that the user switched back to your app or turned the '
'device\'s screen back on while your widget was visible.',
);
},
child: Container(),
);