I have my own app written in Flutter. I used go_router package to ensure a persistent bottom navigation bar. The problem is when I go to qr scanner navigation destination and then go back to another navigation destination B. When I come back to B, I noticed from the logs that the scanner still works in background, which is not good for performances, etc.
Already readed similar questions, but couldn’t solve the problem. Here is the code. Any code suggestion would be appreciated. Thanks in advance!
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp.router(
routerConfig: goRouter,
),
);
}
}
final _rootNavigatorKey = GlobalKey<NavigatorState>();
final _shellHomeNavigatorKey = GlobalKey<NavigatorState>();
final _shellQrNavigatorKey = GlobalKey<NavigatorState>();
final goRouter = GoRouter(initialLocation: '/', navigatorKey: _rootNavigatorKey, routes: [
StatefulShellRoute.indexedStack(
builder: (context, state, navigationShell) {
return ScaffoldWithNestedNavigation(navigationShell: navigationShell);
},
branches: [
StatefulShellBranch(
navigatorKey: _shellHomeNavigatorKey,
routes: [
GoRoute(
path: '/',
pageBuilder: (context, state) => const NoTransitionPage(
child: HomeScreen(label: 'Home'),
),
routes: [
//deep screens
],
),
],
),
StatefulShellBranch(
navigatorKey: _shellQrNavigatorKey,
routes: [
GoRoute(
path: '/qr',
pageBuilder: (context, state) => const NoTransitionPage(
child: QrCodeScreen(label: 'Scan qr-code'),
),
),
],
),
],
),
]);
class ScaffoldWithNestedNavigation extends StatelessWidget {
const ScaffoldWithNestedNavigation({
Key? key,
required this.navigationShell,
}) : super(key: key ?? const ValueKey('ScaffoldWithNestedNavigation'));
final StatefulNavigationShell navigationShell;
void _goBranch(int index) {
navigationShell.goBranch(
index,
initialLocation: index == navigationShell.currentIndex, //to support navigation to initial location
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: navigationShell,
bottomNavigationBar: NavigationBar(
selectedIndex: navigationShell.currentIndex,
destinations: [
NavigationDestination(
label: 'Home',
icon: Icon(Icons.home),
),
const NavigationDestination(label: 'Scan qr-code', icon: Icon(Icons.qr_code_scanner)),
],
onDestinationSelected: _goBranch,
),
);
}
}
class QrCodeScreen extends StatefulWidget {
const QrCodeScreen({
required this.label,
super.key,
});
final String label;
@override
State<StatefulWidget> createState() => QrCodeScreenState();
}
class QrCodeScreenState extends State<QrCodeScreen> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.label),
),
body: const QRScannerHome(),
);
}
}
class QRScannerHome extends StatefulWidget {
const QRScannerHome({super.key});
@override
State<QRScannerHome> createState() => _QRScannerHomeState();
}
class _QRScannerHomeState extends State<QRScannerHome> {
QRViewController? controller;
Barcode? result;
final GlobalKey qrKey = GlobalKey();
@override
void reassemble() {
super.reassemble();
if (Platform.isAndroid) {
controller?.pauseCamera();
}
controller?.resumeCamera();
}
@override
void dispose() {
controller?.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return SizedBox(
height: MediaQuery.of(context).size.height,
child: Stack(
children: [
QRView(
key: qrKey,
onQRViewCreated: _onQRViewCreated,
overlay: QrScannerOverlayShape(
borderRadius: 5,
borderLength: 20,
borderWidth: 5,
cutOutSize: 250),
onPermissionSet: (ctrl, p) => _onPermissionSet(context, ctrl, p),
),
],
),
);
}
void _onQRViewCreated(QRViewController controller) {
setState(() {
this.controller = controller;
});
controller.scannedDataStream.listen((scanData) {
if (scanData.format == BarcodeFormat.qrcode &&
scanData.code!.isNotEmpty) {
controller.pauseCamera();
navigateToNextScreen(scanData.code.toString());
}
});
}
void _onPermissionSet(BuildContext context, QRViewController ctrl, bool p) {
if (!p) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('No Permission')),
);
}
}
void navigateToNextScreen(String qrData) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => QRResult(
scanData: qrData,
),
),
).then((_) {
controller?.resumeCamera();
});
}
}
class QRResult extends StatelessWidget {
const QRResult({super.key, required this.scanData});
final String scanData;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('QR Result'),
),
body: Center(
child: Text(
"Scanned Data: $scanData",
style: const TextStyle(fontSize: 24),
),
),
);
}
}