Reputation: 23035
I am developing a flutter app to read QR Codes. I am using qr_code_scanner: ^0.3.5
library. Below is my code.
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:qr_code_scanner/qr_code_scanner.dart';
class ScanQRCodeScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
title: Text("Scan QR Code"),
),
body: _ScanQRCodeUI());
}
}
class _ScanQRCodeUI extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return _ScanQRCodeUIState();
}
}
class _ScanQRCodeUIState extends State<_ScanQRCodeUI> {
final GlobalKey qrKey = GlobalKey(debugLabel: 'QR');
Barcode result;
QRViewController controller;
// In order to get hot reload to work we need to pause the camera if the platform
// is android, or resume the camera if the platform is iOS.
@override
void reassemble() {
super.reassemble();
if (Platform.isAndroid) {
controller.pauseCamera();
} else if (Platform.isIOS) {
controller.resumeCamera();
}
}
@override
Widget build(BuildContext context) {
return Column(
children: [
Expanded(flex: 4, child: _buildQrView(context)),
Expanded(flex: 1, child: _dataDisplayUI())
],
);
}
Widget _buildQrView(BuildContext context) {
// For this example we check how width or tall the device is and change the scanArea and overlay accordingly.
var scanArea = (MediaQuery.of(context).size.width < 400 ||
MediaQuery.of(context).size.height < 400)
? 200.0
: 400.0;
// To ensure the Scanner view is properly sizes after rotation
// we need to listen for Flutter SizeChanged notification and update controller
return QRView(
key: qrKey,
onQRViewCreated: _onQRViewCreated,
overlay: QrScannerOverlayShape(
borderColor: Colors.red,
borderRadius: 10,
borderLength: 30,
borderWidth: 10,
cutOutSize: scanArea),
);
}
void _onQRViewCreated(QRViewController controller) {
setState(() {
this.controller = controller;
});
controller.scannedDataStream.listen((scanData) async {
print("Hello0");
setState(() {
result = scanData;
print(result.code);
});
// await controller.pauseCamera();
});
}
Widget _dataDisplayUI() {
const yellowColor = const Color(0xffEDE132);
return Column(
children: [
Row(
children: [
Expanded(
flex: 7,
child: Container(
margin:
EdgeInsets.only(top: 30, bottom: 30, left: 10, right: 10),
child:
Text("You have added 12 products. Click here to publish.",
style: GoogleFonts.poppins(
textStyle: TextStyle(
color: Colors.black,
fontWeight: FontWeight.normal,
fontSize: 14,
))),
)),
Expanded(
flex: 3,
child: Container(
width: 60,
height: 60,
child: Center(
child: Text("12",
style: GoogleFonts.poppins(
textStyle: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
fontSize: 21,
)))),
decoration:
BoxDecoration(shape: BoxShape.circle, color: yellowColor),
))
],
)
],
);
}
@override
void dispose() {
controller?.dispose();
super.dispose();
}
}
I am using this app to scan products one by one, just like how the cashier does in a super marker using a barcode scanner.
The issue is, this scanner is listening to a stream
and it is keep on running. Pay your attention to the _onQRViewCreated
method. As a result, the same QR is being read multiple times before we even move the camera to the next QR code.
How can I make sure there is a delay between 2 scans? For an example, when I scan for a QR Code, I have to wait for another 2 seconds to scan the next QR.
If my idea of creating a delay between 2 scans is wrong, I am open for other ideas as well.
Upvotes: 4
Views: 3652
Reputation: 141
Another way would be to use DateTime to check and see if the time difference between the current scan and the last scan is under a specified amount (say 3 seconds). If so, we don't set the state to the new scanData. In effect, this puts a 3-second delay between each QR code scan. See the code below.
controller.scannedDataStream.listen((scanData) {
final currentScan = DateTime.now();
if (lastScan == null || currentScan.difference(lastScan!) > const Duration(seconds: 3))
{
lastScan = currentScan;
print(scanData.code);
setState(() {
result = scanData;
print('the qr just read was ' + scanData.code);
});
}
});
}
Upvotes: 1
Reputation: 235
You can use
controller.scannedDataStream.first
that stops listening to other events from the stream.
Another solution would be to set an internal state property like below:
bool QrBeingProcessed = false;
and when you scan the first qr set it to true, till you're done.
Upvotes: 1