Skip to content

Instantly share code, notes, and snippets.

@saliouseck2009
Last active September 26, 2024 06:28
Show Gist options
  • Save saliouseck2009/8dfd10145a73c5e5e61998e23de13753 to your computer and use it in GitHub Desktop.
Save saliouseck2009/8dfd10145a73c5e5e61998e23de13753 to your computer and use it in GitHub Desktop.
Flutter Barcode Scanner with Mobile Scanner
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:mobile_scanner/mobile_scanner.dart';
class ScannerWidget extends StatefulWidget {
final String? title;
final void Function(String value) onScan;
const ScannerWidget({super.key, required this.onScan, this.title,});
@override
State<ScannerWidget> createState() => _ScannerState();
}
class _ScannerState extends State<ScannerWidget> with WidgetsBindingObserver {
final MobileScannerController controller = MobileScannerController(
autoStart: false,
torchEnabled: false,
useNewCameraSelector: true,
);
StreamSubscription<Object?>? _subscription;
void _handleBarcode(BarcodeCapture barcodes) {
if (mounted) {
final String? value = barcodes.barcodes.firstOrNull?.displayValue?.trim();
if(value != null) {
widget.onScan(value);
controller.stop();
}
}
}
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
_subscription = controller.barcodes.listen(_handleBarcode);
unawaited(controller.start());
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
if (!controller.value.isInitialized) {
return;
}
switch (state) {
case AppLifecycleState.detached:
case AppLifecycleState.hidden:
case AppLifecycleState.paused:
return;
case AppLifecycleState.resumed:
_subscription = controller.barcodes.listen(_handleBarcode);
unawaited(controller.start());
case AppLifecycleState.inactive:
unawaited(_subscription?.cancel());
_subscription = null;
unawaited(controller.stop());
}
}
@override
Widget build(BuildContext context) {
final String title = widget.title ?? 'scan_your_badge';
return Scaffold(
backgroundColor: Colors.white,
body: Stack(
children: [
Align(
alignment: Alignment.center,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
width: 300,
height: 300,
alignment: Alignment.topCenter,
decoration: BoxDecoration(
border: Border.all(color: Colors.blue, width: 4),
color: Colors.blue,
),
padding: const EdgeInsets.all(5),
child: MobileScanner(
controller: controller,
errorBuilder: (context, error, child) {
return Center(child: Text(error.toString()));
},
fit: BoxFit.fill,
),
),
const SizedBox(height: 25),
Center(
child: Container(
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 15),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10),
),
child: Text(
title,
style: const TextStyle(fontSize: 16),
),
),
),
]
),
),
Align(
alignment: Alignment.bottomCenter,
child: Container(
alignment: Alignment.center,
height: 100,
color: Colors.black.withOpacity(0.4),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ToggleFlashlightButton(controller: controller),
],
),
),
),
],
),
);
}
@override
Future<void> dispose() async {
WidgetsBinding.instance.removeObserver(this);
unawaited(_subscription?.cancel());
_subscription = null;
super.dispose();
await controller.dispose();
}
}
class ToggleFlashlightButton extends StatelessWidget {
const ToggleFlashlightButton({required this.controller, super.key});
final MobileScannerController controller;
@override
Widget build(BuildContext context) {
return ValueListenableBuilder(
valueListenable: controller,
builder: (context, state, child) {
if (!state.isInitialized || !state.isRunning) {
return const SizedBox.shrink();
}
switch (state.torchState) {
case TorchState.auto:
return IconButton(
color: Colors.white,
iconSize: 32.0,
icon: const Icon(Icons.flash_auto),
onPressed: () async {
await controller.toggleTorch();
},
);
case TorchState.off:
return IconButton(
color: Colors.white,
iconSize: 32.0,
icon: const Icon(Icons.flash_off),
onPressed: () async {
await controller.toggleTorch();
},
);
case TorchState.on:
return IconButton(
color: Colors.white,
iconSize: 32.0,
icon: const Icon(Icons.flash_on),
onPressed: () async {
await controller.toggleTorch();
},
);
case TorchState.unavailable:
return const Icon(
Icons.no_flash,
color: Colors.grey,
);
}
},
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment