Navaron Bracke

update barcode scanner window sample

... ... @@ -16,16 +16,75 @@ class BarcodeScannerWithScanWindow extends StatefulWidget {
class _BarcodeScannerWithScanWindowState
extends State<BarcodeScannerWithScanWindow> {
late MobileScannerController controller = MobileScannerController();
Barcode? barcode;
BarcodeCapture? capture;
final MobileScannerController controller = MobileScannerController();
Future<void> onDetect(BarcodeCapture barcode) async {
capture = barcode;
setState(() => this.barcode = barcode.barcodes.first);
@override
void initState() {
super.initState();
controller.start();
}
Widget _buildBarcodeOverlay() {
return ValueListenableBuilder(
valueListenable: controller,
builder: (context, value, child) {
// Not ready.
if (!value.isInitialized || !value.isRunning || value.error != null) {
return const SizedBox();
}
return StreamBuilder<BarcodeCapture>(
stream: controller.barcodes,
builder: (context, snapshot) {
final BarcodeCapture? barcodeCapture = snapshot.data;
// No barcode.
if (barcodeCapture == null || barcodeCapture.barcodes.isEmpty) {
return const SizedBox();
}
MobileScannerArguments? arguments;
final scannedBarcode = barcodeCapture.barcodes.first;
// No barcode corners, or size, or no camera preview size.
if (scannedBarcode.corners.isEmpty ||
value.size.isEmpty ||
barcodeCapture.size.isEmpty) {
return const SizedBox();
}
return CustomPaint(
painter: BarcodeOverlay(
barcodeCorners: scannedBarcode.corners,
barcodeSize: barcodeCapture.size,
boxFit: BoxFit.contain,
cameraPreviewSize: value.size,
),
);
},
);
},
);
}
Widget _buildScanWindow(Rect scanWindowRect) {
return ValueListenableBuilder(
valueListenable: controller,
builder: (context, value, child) {
// Not ready.
if (!value.isInitialized ||
!value.isRunning ||
value.error != null ||
value.size.isEmpty) {
return const SizedBox();
}
return CustomPaint(
painter: ScannerOverlay(scanWindowRect),
);
},
);
}
@override
Widget build(BuildContext context) {
... ... @@ -34,77 +93,69 @@ class _BarcodeScannerWithScanWindowState
width: 200,
height: 200,
);
return Scaffold(
appBar: AppBar(title: const Text('With Scan window')),
backgroundColor: Colors.black,
body: Builder(
builder: (context) {
return Stack(
body: Stack(
fit: StackFit.expand,
children: [
MobileScanner(
fit: BoxFit.contain,
scanWindow: scanWindow,
controller: controller,
onScannerStarted: (arguments) {
setState(() {
this.arguments = arguments;
});
},
errorBuilder: (context, error, child) {
return ScannerErrorWidget(error: error);
},
onDetect: onDetect,
),
if (barcode != null &&
barcode?.corners != null &&
arguments != null)
CustomPaint(
painter: BarcodeOverlay(
barcode: barcode!,
arguments: arguments!,
boxFit: BoxFit.contain,
capture: capture!,
),
),
CustomPaint(
painter: ScannerOverlay(scanWindow),
),
_buildBarcodeOverlay(),
_buildScanWindow(scanWindow),
Align(
alignment: Alignment.bottomCenter,
child: Container(
alignment: Alignment.bottomCenter,
alignment: Alignment.center,
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
height: 100,
color: Colors.black.withOpacity(0.4),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Center(
child: SizedBox(
width: MediaQuery.of(context).size.width - 120,
height: 50,
child: FittedBox(
child: Text(
barcode?.displayValue ?? 'Scan something!',
child: StreamBuilder<BarcodeCapture>(
stream: controller.barcodes,
builder: (context, snapshot) {
final barcodeCapture = snapshot.data;
String displayValue = 'Scan something!';
if (barcodeCapture != null &&
barcodeCapture.barcodes.isNotEmpty) {
final String? value =
barcodeCapture.barcodes.first.displayValue;
if (value != null) {
displayValue = value;
}
}
return Text(
displayValue,
overflow: TextOverflow.fade,
style: Theme.of(context)
.textTheme
.headlineMedium!
.copyWith(color: Colors.white),
),
),
),
),
],
);
},
),
),
),
],
);
},
),
);
}
@override
Future<void> dispose() async {
await controller.dispose();
super.dispose();
}
}
class ScannerOverlay extends CustomPainter {
... ... @@ -114,6 +165,8 @@ class ScannerOverlay extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
// TODO: use `Offset.zero & size` instead of Rect.largest
// we need to pass the size to the custom paint widget
final backgroundPath = Path()..addRect(Rect.largest);
final cutoutPath = Path()..addRect(scanWindow);
... ... @@ -151,7 +204,9 @@ class BarcodeOverlay extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
if (barcodeCorners.isEmpty) {
if (barcodeCorners.isEmpty ||
barcodeSize.isEmpty ||
cameraPreviewSize.isEmpty) {
return;
}
... ...