qrcode_scan_page.dart 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. import 'dart:io';
  2. import 'package:flutter/cupertino.dart';
  3. import 'package:flutter/material.dart';
  4. import 'package:flutter/services.dart';
  5. import 'package:flutter/widgets.dart';
  6. import 'package:lszlgl/page/sample_task/reap_sample_detail/reap_sample_task_page.dart';
  7. import 'package:qr_code_scanner/qr_code_scanner.dart';
  8. import '../../base/base_lifecycle_state.dart';
  9. import '../../widget/button.dart';
  10. class QrCodeScanPage extends StatefulWidget {
  11. const QrCodeScanPage({super.key});
  12. @override
  13. State<QrCodeScanPage> createState() => _QrCodeScanPageState();
  14. }
  15. class _QrCodeScanPageState extends BaseLifecycleState<QrCodeScanPage> with SingleTickerProviderStateMixin {
  16. final GlobalKey qrKey = GlobalKey(debugLabel: 'QR');
  17. Barcode? result;
  18. QRViewController? controller;
  19. late AnimationController _ctrl;
  20. late Animation<Offset> animation;
  21. void _onQRViewCreated(QRViewController controller) {
  22. this.controller = controller;
  23. controller.scannedDataStream.listen((scanData) {
  24. debugPrint('code:${scanData.code} format:${scanData.format} rawBytes:${scanData.rawBytes}');
  25. controller.pauseCamera();
  26. parseCode(scanData);
  27. });
  28. }
  29. void parseCode(Barcode data) {
  30. String code = data.code ?? '';
  31. if (code.isEmpty) {
  32. showErrorDialog('内容为空,请扫描正确二维码');
  33. return;
  34. }
  35. // 121.36.17.6:19090/admin-api/zj/code-sampling-task-details-sgjc/getSamplingTaskDetails?id=47106
  36. List<String> split = code.split('?');
  37. if (!code.contains('?') || split.length <= 1 || !split[0].contains('/')) {
  38. showErrorDialog(code);
  39. return;
  40. }
  41. String api = split[0].split('/').last;
  42. Map<String, String> params = {};
  43. for (String value in split[1].split('&')) {
  44. List<String> kv = value.split('=');
  45. params[kv[0]] = kv[1];
  46. }
  47. switch (api) {
  48. case 'getSamplingTaskDetails':
  49. // 收获扦样详情
  50. if (params['id'] == null) {
  51. showErrorDialog(code);
  52. return;
  53. }
  54. MyRouter.startReapSampleTask(
  55. args: ReapSampleTaskPageArgs(id: num.parse(params['id']!), detail: true),
  56. replace: true,
  57. );
  58. default:
  59. showErrorDialog(code);
  60. }
  61. }
  62. void showErrorDialog(String msg) async {
  63. await showDialog(
  64. context: context,
  65. builder: (_) => AlertDialog(
  66. title: Text(msg),
  67. actions: [MyButton('确定', alignment: null, onTap: () => MyNavigator.pop())],
  68. ),
  69. );
  70. controller?.resumeCamera();
  71. }
  72. // In order to get hot reload to work we need to pause the camera if the platform
  73. // is android, or resume the camera if the platform is iOS.
  74. @override
  75. void reassemble() {
  76. super.reassemble();
  77. if (Platform.isAndroid) {
  78. controller!.pauseCamera();
  79. } else if (Platform.isIOS) {
  80. controller!.resumeCamera();
  81. }
  82. }
  83. @override
  84. void dispose() {
  85. controller?.dispose();
  86. _ctrl.dispose();
  87. super.dispose();
  88. }
  89. @override
  90. void initState() {
  91. super.initState();
  92. // 创建动画控制器
  93. _ctrl = AnimationController(
  94. vsync: this,
  95. duration: const Duration(seconds: 2),
  96. );
  97. animation = Tween<Offset>(
  98. begin: const Offset(0, -0.25),
  99. end: const Offset(0, 0.25),
  100. ).animate(_ctrl);
  101. _ctrl.repeat();
  102. }
  103. @override
  104. Widget build(BuildContext context) {
  105. return myScaffold(child: buildBody());
  106. }
  107. Widget buildBody() {
  108. return AnnotatedRegion<SystemUiOverlayStyle>(
  109. value: SystemUiOverlayStyle.light,
  110. child: Stack(
  111. fit: StackFit.expand,
  112. children: [
  113. // myAppBar(
  114. // title: '扫一扫',
  115. // actions: [buildFlash()],
  116. // ),
  117. Positioned.fill(
  118. child: QRView(
  119. key: qrKey,
  120. onQRViewCreated: _onQRViewCreated,
  121. ),
  122. ),
  123. Positioned(
  124. top: 0,
  125. left: 0,
  126. right: 0,
  127. child: buildAppBar(),
  128. ),
  129. SlideTransition(
  130. position: animation,
  131. child: Image.asset(imgScanScanning, width: double.infinity),
  132. ),
  133. ],
  134. ),
  135. );
  136. }
  137. Widget buildAppBar() {
  138. return Padding(
  139. padding: EdgeInsets.only(top: MediaQuery.of(context).padding.top),
  140. child: Stack(
  141. alignment: Alignment.center,
  142. children: [
  143. Positioned(left: 0, child: buildBack()),
  144. const Text(
  145. '扫一扫',
  146. textAlign: TextAlign.center,
  147. style: TextStyle(color: Colors.white, fontSize: 20),
  148. ),
  149. Positioned(
  150. right: 0,
  151. child: buildFlash(),
  152. ),
  153. ],
  154. ),
  155. );
  156. }
  157. Widget buildBack() {
  158. return GestureDetector(
  159. onTap: () => MyNavigator.pop(),
  160. child: Padding(
  161. padding: const EdgeInsets.symmetric(horizontal: 16),
  162. child: Image.asset(imgScanBack, width: 24, height: 24),
  163. ),
  164. );
  165. }
  166. Widget buildFlash() {
  167. return GestureDetector(
  168. onTap: () => controller?.toggleFlash(),
  169. behavior: HitTestBehavior.opaque,
  170. child: Padding(
  171. padding: const EdgeInsets.symmetric(horizontal: 16),
  172. child: Row(
  173. children: [
  174. Image.asset(imgScanFlash, width: 24, height: 24),
  175. const Text(
  176. '闪光灯',
  177. textAlign: TextAlign.center,
  178. style: TextStyle(color: Colors.white, fontSize: 14),
  179. ),
  180. ],
  181. ),
  182. ),
  183. );
  184. }
  185. }