Severe glitch when navigating to a screen with google_mobile_ads - android

Upgrading to Flutter 2.8.1 causes flickering when navigating between screens in apps that contain ads. In particular, the flickering happens when navigating to a new screen from another screen that has a banner ad. When commenting out the banner the flickering goes away.
The problem is not producible using Flutter 2.5.3.
The issue was originally raised in googleads-mobile-flutter but after investigating the issue further it is now believed to be a problem with the Flutter SDK.
To produce the problem, run the attached application code using google_mobile_ads: 1.0.1 and Flutter 2.8.0.
Video sample, code sample and flutter doctor -v output produced by #maheshmnj
Code sample:
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return const MaterialApp(home: HomeScreen());
}
}
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key}) : super(key: key);
#override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Expanded(child: ListView.builder(itemBuilder: (context, index) {
return ListTile(
title: Text('Item $index'),
onTap: () {
Navigator.push(context, MaterialPageRoute(builder: (context) {
return const ProducDetailPage();
}));
},
);
})),
const CustomBannerAd()
],
),
);
}
}
class ProducDetailPage extends StatelessWidget {
const ProducDetailPage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Produc Detail'),
),
body: Column(children: const [
SizedBox(
height: 150,
child: Placeholder(
color: Colors.red,
),
),
SizedBox(
height: 150,
child: Placeholder(
color: Colors.green,
),
),
CustomBannerAd()
]));
}
}
class CustomBannerAd extends StatefulWidget {
const CustomBannerAd({Key? key}) : super(key: key);
#override
_CustomBannerAdState createState() => _CustomBannerAdState();
}
class _CustomBannerAdState extends State<CustomBannerAd> {
BannerAd? _anchoredAdaptiveAd;
var _isLoaded = false;
late Orientation _currentOrientation;
#override
void didChangeDependencies() {
super.didChangeDependencies();
_currentOrientation = MediaQuery.of(context).orientation;
_loadAd();
}
#override
void dispose() {
super.dispose();
_anchoredAdaptiveAd?.dispose();
}
Future<void> _loadAd() async {
await _anchoredAdaptiveAd?.dispose();
if (mounted) {
setState(() {
_anchoredAdaptiveAd = null;
_isLoaded = false;
});
}
final AnchoredAdaptiveBannerAdSize? size =
await AdSize.getCurrentOrientationAnchoredAdaptiveBannerAdSize(
MediaQuery.of(context).size.width.truncate());
if (size == null) {
debugPrint('Unable to get height of anchored banner.');
return;
}
_anchoredAdaptiveAd = BannerAd(
adUnitId: Platform.isAndroid
? 'ca-app-pub-3940256099942544/6300978111'
: 'ca-app-pub-3940256099942544/2934735716',
size: size,
request: const AdRequest(
nonPersonalizedAds: false,
),
listener: BannerAdListener(
onAdLoaded: (Ad ad) {
debugPrint("Ad loaded");
if (mounted) {
setState(() {
_anchoredAdaptiveAd = ad as BannerAd;
_isLoaded = true;
});
}
},
onAdFailedToLoad: (Ad ad, LoadAdError error) {
debugPrint('$BannerAd failedToLoad: $error');
ad.dispose();
},
onAdOpened: (Ad ad) => debugPrint('$BannerAd onAdOpened.'),
onAdClosed: (Ad ad) => debugPrint('$BannerAd onAdClosed.'),
),
);
return _anchoredAdaptiveAd?.load();
}
#override
Widget build(BuildContext context) {
return OrientationBuilder(builder: (context, orientation) {
if (_currentOrientation == orientation &&
_anchoredAdaptiveAd != null &&
_isLoaded) {
return Container(
color: Colors.transparent,
width: _anchoredAdaptiveAd!.size.width.toDouble(),
height: _anchoredAdaptiveAd?.size.height.toDouble(),
child: AdWidget(ad: _anchoredAdaptiveAd!),
);
}
// Reload the ad if the orientation changes.
if (_currentOrientation != orientation) {
_currentOrientation = orientation;
_loadAd();
}
return const SizedBox.shrink();
});
}
}
is there any solution?
Screenshots and videos

change your google_mobile_ads plugin with this :
google_mobile_ads:
git:
url: https://github.com/SuaMusica/googleads-mobile-flutter.git
path: packages/google_mobile_ads
ref: feature/suamusica
if there is a yellow underscore in git text, just add the following code to pubspec.yaml
publish_to: 'none'

I also faced the same issue. And it's only when you used fluter sdk 2.8 to 2.10. It's also raised on flutter github repo. (https://github.com/flutter/flutter/issues/95343).
The solution is to upgrade flutter sdk to 3.0.2 and update google_mobile_ads 1.3.0.

Related

Passing captured image between pages in flutter

I'm having problems with my code as I'm getting undefined_identifier errors.
I'm trying to pass the image I captured from 'GeneratedGroup1Widget1.dart' using 'flutter_screenutils' to 'GeneratedResultsWidget.dart'. However, my route in 'main.dart' doesn't define the image variable inside my parameter. I've been trying to fix this error for 10 hours now. Please help. Thanks in advance!
Error: (main.dart)
Undefined name 'image'.
Try correcting the name to one that is defined, or defining the name.
Here are my codes:
'GeneratedGroup1Widget1.dart'
class GeneratedGroup1Widget1 extends StatefulWidget {
#override
_GeneratedGroup1Widget1State createState() => _GeneratedGroup1Widget1State();
}
class _GeneratedGroup1Widget1State extends State<GeneratedGroup1Widget1> {
Future _pickImage() async {
final imageSource = await showDialog<ImageSource>(
context: context,
builder: (context) => SimpleDialog(
title: const Text('Select Image Source'),
children: [
SimpleDialogOption(
onPressed: () => Navigator.pop(context, ImageSource.camera),
child: const Text('Camera'),
),
SimpleDialogOption(
onPressed: () => Navigator.pop(context, ImageSource.gallery),
child: const Text('Gallery'),
),
],
),
);
if (imageSource != null) {
final image = await ImagePicker().pickImage(source: imageSource);
Navigator.pushNamed(context, '/GeneratedResultsWidget', arguments: image);
}
}
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () => _pickImage(),
child: Container(
....
'GeneratedResultsWidget.dart'
class GeneratedResultsWidget extends StatelessWidget {
final XFile file;
const GeneratedResultsWidget({required Key key, required this.file})
: super(key: key);
#override
Widget build(BuildContext context) {
if (file == null) {
return Scaffold(body: Center(child: Text('No Image selected')));
} else {
return Scaffold(body: Center(child: Text(file.path)));
}
}
}
class GeneratedResultsWidget1 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Material(
...
'main.dart'
void main() {
runApp(FoodClassifierApp());
}
class FoodClassifierApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ScreenUtilInit(
designSize: Size(360, 640),
builder: (BuildContext context, child) => MaterialApp(
title: 'food-classifier',
theme: ThemeData(
primarySwatch: Colors.blue,
),
initialRoute: '/GeneratedHomepageWidget',
routes: {
'/GeneratedScanWidget': (context) => GeneratedScanWidget(),
'/GeneratedResultsWidget': (context) =>
GeneratedResultsWidget(key: UniqueKey(), file: image),
'/GeneratedHomepageWidget': (context) => GeneratedHomepageWidget(),
'/GeneratedFoodlistWidget': (context) => GeneratedFoodlistWidget(),
},
),
);
}
}
This is my first time coding in flutter and I used figma to generate my widgets.

In android emulator video doesn't show (Flutter)

My problem is that the video works fine on web view but doesn't show or work in the Android emulator. I want to play this video in an emulator also. And all the videos are asset videos. If anyone knows the solution or if anyone can help please help. Thank You
**Below is the code which I wrote for the video **
import 'package:flutter/material.dart';
import 'package:video_player/video_player.dart';
import 'package:cached_video_player/cached_video_player.dart';
class VideoApp extends StatefulWidget {
const VideoApp({Key? key}) : super(key: key);
#override
State<VideoApp> createState() => _VideoAppState();
}
class _VideoAppState extends State<VideoApp> {
late VideoPlayerController _controller;
late Future<void> _initializeVideoPlayerFuture;
#override
void initState() {
super.initState();
// Create and store the VideoPlayerController. The VideoPlayerController
// offers several different constructors to play videos from assets, files,
// or the internet.
_controller = VideoPlayerController.network(
'assets/videos/animation 1 final.mp4',
);
_initializeVideoPlayerFuture = _controller.initialize();
}
#override
void dispose() {
// Ensure disposing of the VideoPlayerController to free up resources.
_controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder(
future: _initializeVideoPlayerFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return AspectRatio(
aspectRatio: _controller.value.aspectRatio,
child: VideoPlayer(_controller),
);
} else {
return const Center(
child: CircularProgressIndicator(),
);
}
},
),
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(() {
if (_controller.value.isPlaying) {
_controller.pause();
} else {
// If the video is paused, play it.
_controller.play();
}
});
},
// Display the correct icon depending on the state of the player.
child: Icon(
_controller.value.isPlaying ? Icons.pause : Icons.play_arrow,
),
)
);
}
}
[https://i.stack.imgur.com/8X0OX.png][1]
Your are calling from network but giving an asset path.
_controller = VideoPlayerController.network(
'assets/videos/animation 1 final.mp4',
);

how create a RIVE animation with flutter

I want to create a RIVE animation with flutter. I followed a tutorial in YouTube. I wrote the same thing but when I execute two errors is displayed
(RiveFile.import (data);
file.mainArtboard;)
Here is the code:
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:rive/rive.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: MyPage(),
);
}
}
class MyPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Using Rive'),
),
body: RocketContainer());
}
}
class RocketContainer extends StatefulWidget {
#override
_RocketContainerState createState() => _RocketContainerState();
}
class _RocketContainerState extends State<RocketContainer> {
Artboard _artboard;
RiveAnimationController _rocketController;
#override
void initState() {
_loadRiveFile();
super.initState();
}
void _loadRiveFile() async {
final bytes = await rootBundle.load('assets/rocket.riv');
final file = RiveFile.import(bytes);
setState(() {
_artboard = file.mainArtboard;
});
}
void _launch() async {
_artboard.addController(
_rocketController = SimpleAnimation('launch'),
);
setState(() => _rocketController.isActive = true);
}
void _fall() async {
_artboard.addController(
_rocketController = SimpleAnimation('fall'),
);
setState(() => _rocketController.isActive = true);
}
#override
Widget build(BuildContext context) {
return Column(
children: [
Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height - 250,
child: _artboard != null
? Rive(
artboard: _artboard,
fit: BoxFit.cover,
)
: Container()),
TextButton(onPressed: () => _launch(), child: Text('launch')),
TextButton(onPressed: () => _fall(), child: Text('fall'))
],
);
}
}
errors:
The current Dart SDK version is 2.10.5.
Because animation depends on cupertino_icons >=1.0.1 which requires SDK version >=2.12.0-0 <3.0.0, version solving failed.
pub get failed (1; Because animation depends on cupertino_icons >=1.0.1 which requires SDK version >=2.12.0-0 <3.0.0, version solving failed.)
*error: Instance member 'import' can't be accessed using static access. (static_access_to_instance_member at [animation] lib\main.dart:47)
*error: The getter 'mainArtboard' isn't defined for the type 'bool'. (undefined_getter at [animation] lib\main.dart:50)
You could have a look at the example provided with the updated and latest documentation of Rive in their official Github repository.
Control playing and pausing a looping animation:
import 'package:flutter/material.dart';
import 'package:rive/rive.dart';
class PlayPauseAnimation extends StatefulWidget {
const PlayPauseAnimation({Key? key}) : super(key: key);
#override
_PlayPauseAnimationState createState() => _PlayPauseAnimationState();
}
class _PlayPauseAnimationState extends State<PlayPauseAnimation> {
// Controller for playback
late RiveAnimationController _controller;
// Toggles between play and pause animation states
void _togglePlay() =>
setState(() => _controller.isActive = !_controller.isActive);
/// Tracks if the animation is playing by whether controller is running
bool get isPlaying => _controller.isActive;
#override
void initState() {
super.initState();
_controller = SimpleAnimation('idle');
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: RiveAnimation.network(
'https://cdn.rive.app/animations/vehicles.riv',
controllers: [_controller],
// Update the play state when the widget's initialized
onInit: () => setState(() {}),
),
),
floatingActionButton: FloatingActionButton(
onPressed: _togglePlay,
tooltip: isPlaying ? 'Pause' : 'Play',
child: Icon(
isPlaying ? Icons.pause : Icons.play_arrow,
),
),
);
}
}
To play an animation from an asset bundle, use:
RiveAnimation.asset('assets/vehicles.riv'
in place of
RiveAnimation.network('https://cdn.rive.app/animations/vehicles.riv',
This line:
_controller = SimpleAnimation('idle');
attempts to play an animation called 'idle'. If your animation is named differently, try replacing the name here.

How to use barcode_scan widget as a child to some other widget?

I am using barcode_scan widget in my flutter app when I call Scan method this widget takes up the whole screen where it show the camera, I want to show that camera view inside another widget.
You can use package https://pub.dev/packages/last_qr_scanner or https://pub.dev/packages/qr_code_scanner
They both use platform view within Flutter
full example code of last_qr_scanner
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:last_qr_scanner/last_qr_scanner.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
const MyApp({
Key key,
}) : super(key: key);
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final GlobalKey qrKey = GlobalKey(debugLabel: 'QR');
var qrText = "";
var controller;
#override
void initState() {
super.initState();
}
void _onQRViewCreated(QRViewController controller) {
this.controller = controller;
final channel = controller.channel;
controller.init(qrKey);
channel.setMethodCallHandler((MethodCall call) async {
switch (call.method) {
case "onRecognizeQR":
dynamic arguments = call.arguments;
setState(() {
qrText = arguments.toString();
});
}
});
}
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: new Scaffold(
appBar: new AppBar(
title: new Text('Barcode Scanner Example'),
),
body: Column(
children: <Widget>[
Expanded(
child: LastQrScannerPreview(
key: qrKey,
onQRViewCreated: _onQRViewCreated,
),
flex: 4,
),
Expanded(
child: Text("This is the result of scan: $qrText"),
flex: 1,
),
Expanded(
child: RaisedButton(
onPressed: () {
this.controller.toggleTorch();
},
child: Text("Toggle Torch"),
),
flex: 1,
)
],
),
),
);
}
}
Your camera view must be a flutter widget to be embedded in another widget.
You can use this package which outputs the camera preview on a flutter texture and use the Mobile Vision API to detect QR codes and barcodes : https://github.com/rmtmckenzie/flutter_qr_mobile_vision

Flutter Bluetooth External Barcode Scanner

I need to use an external barcode scanner which is connected via Bluetooth to my device (it is recognized as a keyboard). It works well and I can get the content of a barcode inside a TextField.
The problem is that I need to set the focus to the TextField in order to get the content of the barcode... Is there a way for the current screen to listen to the keyboard event that way I could get the data without wasting time selecting the TextField?
Might be too late but you can set the TextField autofocus prop to true.
TextField(
autofocus:true,
)
You can use this example code for RawKeyboardListener:
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
static const String _title = 'RawKeyboardListener';
#override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
home: Scaffold(
appBar: AppBar(title: const Text(_title)),
body: const MyStatefulWidget(),
),
);
}
}
class MyStatefulWidget extends StatefulWidget {
const MyStatefulWidget({Key? key}) : super(key: key);
#override
State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
final FocusNode _focusNode = FocusNode();
String _controller = '';
String? _message;
#override
void dispose() {
_focusNode.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
FocusScope.of(context).requestFocus(_focusNode);
final TextTheme textTheme = Theme.of(context).textTheme;
return Container(
color: Colors.white,
alignment: Alignment.center,
child: DefaultTextStyle(
style: textTheme.bodyText1!,
child: RawKeyboardListener(
focusNode: _focusNode,
onKey: (RawKeyEvent event) {
if (event is RawKeyDownEvent) {
if (event.physicalKey == PhysicalKeyboardKey.enter) {
print('ENTER');
setState(() {
_message = _controller;
_controller = '';
});
} else {
print(
'_handleKeyEvent Event data keyLabel ${event.data.keyLabel}');
_controller += event.data.keyLabel;
}
print('controller: $_controller');
}
},
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
_message ?? 'Press a key',
),
Text(
'${_message?.length}',
),
],
),
),
),
);
}
}
You can use TextEditingController for TextFormField

Categories

Resources