import 'dart:io'; import 'dart:typed_data'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:getx_scaffold/getx_scaffold.dart'; import 'package:image/image.dart' as img; import 'package:image_picker/image_picker.dart'; import 'package:qr_code_scanner_plus/qr_code_scanner_plus.dart'; import 'package:zxing_lib/common.dart'; import 'package:zxing_lib/qrcode.dart'; import 'package:zxing_lib/zxing.dart'; class QrCodeController extends GetxController with BaseControllerMixin, GetSingleTickerProviderStateMixin { @override String get builderId => 'qrcode'; // --- Animation --- late final AnimationController animationController; late final Animation scanAnimation; // --- QR Scanning --- final GlobalKey qrKey = GlobalKey(debugLabel: 'QR'); QRViewController? qrViewController; final Rx result = Rx(null); final RxBool isFlashOn = false.obs; @override void onInit() { super.onInit(); requestPermission(); animationController = AnimationController( duration: const Duration(milliseconds: 2500), vsync: this, ); scanAnimation = Tween(begin: 0, end: 1).animate(animationController); animationController.repeat(reverse: false); } /// 当 QRView 创建时调用 void onQRViewCreated(QRViewController controller) { this.qrViewController = controller; // 监听扫描到的数据 controller.scannedDataStream.listen((scanData) { if (scanData.code != null && result.value?.code != scanData.code) { result.value = scanData; qrViewController?.pauseCamera(); animationController.stop(); renderResult(scanData.code!); } }); } void resumeScanner() { result.value = null; qrViewController?.resumeCamera(); animationController.repeat(reverse: false); } /// 从相册选择图片并扫描二维码 void scanFromGallery() async { try { final XFile? imageFile = await ImagePicker().pickImage(source: ImageSource.gallery); if (imageFile == null) return; // 用户取消了选择 qrViewController?.pauseCamera(); animationController.stop(); String? scanResult; try { final image = img.decodeImage(await File(imageFile.path).readAsBytes()); if (image != null) { //扫描图片 final pixels = Int32List.fromList( image.map((pixel) { return (pixel.a.toInt() << 24) | (pixel.r.toInt() << 16) | (pixel.g.toInt() << 8) | pixel.b.toInt(); }).toList(), ); final source = RGBLuminanceSource(image.width, image.height, pixels); final bitmap = BinaryBitmap(HybridBinarizer(source)); final reader = QRCodeReader(); final result = reader.decode(bitmap); scanResult = result.text; } } on NotFoundException { scanResult = null; } catch (e) { //异常 scanResult = null; } if (scanResult != null) { renderResult(scanResult); } else { showErrorToast('未识别到二维码'); resumeScanner(); } } catch (e) { showErrorToast('从相册选择失败'); resumeScanner(); } } /// 切换闪光灯 void toggleFlash() async { await qrViewController?.toggleFlash(); isFlashOn.value = (await qrViewController?.getFlashStatus()) ?? false; } /// 翻转相机 void flipCamera() async { await qrViewController?.flipCamera(); } void requestPermission() async { final List results = await Future.wait([ requestCameraPermission(), requestPhotosPermission(), ]); final isCameraGranted = results[0]; final isPhotosGranted = results[1]; if (!isCameraGranted) { showErrorToast('相机权限未被授予,请到权限管理中打开'); } if (!isPhotosGranted) { showErrorToast( '相册权限未被授予,请到权限管理中打开', ); } } //扫码结果处理 void renderResult(String resultStr) { Get.defaultDialog( title: "扫描结果", middleText: resultStr, onConfirm: () { Get.back(); resumeScanner(); }, onCancel: () { resumeScanner(); }, ); } @override void onClose() { qrViewController?.dispose(); animationController.dispose(); super.onClose(); } }