flutter扫描二维码或者条形码

2,187 阅读2分钟

flutter扫描二维码或者条形码

扫码功能

1、mobile_scanner,该插件同时支持二维码和条形码,但是使用捆绑版本会使Android打包变大 3-10M,非捆版版本会增加 600kb左右,具体可前往官网查看。

image.png 2、扫码需要相机权限,打包时注意加入相关权限即可。官网有很多其它用法本地图片扫描、返回图片等功能,可以自行去探索,这里只介绍最基础的用法,对官网最简单的用法稍作封装:
  • 引入必要的包
  • 通过 onScanCompleted 回调函数把扫描结果传给上级页面
import 'package:flutter/material.dart';
import 'package:mobile_scanner/mobile_scanner.dart';
import 'package:wallpaper/components/scan_code_animation%20.dart';

class ScanCode extends StatefulWidget {
  final void Function(String result) onScanCompleted;
  const ScanCode({super.key, required this.onScanCompleted});

  @override
  State<ScanCode> createState() => _ScanCode();
}

class _ScanCode extends State<ScanCode> {
  Barcode? _barcode;
  final MobileScannerController controller = MobileScannerController();

  void _handleBarcode(BarcodeCapture barcodes) async {
    if (mounted) {
      final barcode = barcodes.barcodes.firstOrNull;
      if (barcode != null) {
        // 更新状态
        setState(() {
          _barcode = barcode;
        });

        // 调用回调函数
        widget.onScanCompleted(barcode.displayValue ?? '');

        // 停止扫描并返回
        await controller.stop();
        // ignore: use_build_context_synchronously
        Navigator.pop(context);
      }
    }
  }

  @override
  void dispose() {
    controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('扫描二维码或者条形码')),
      backgroundColor: Colors.black,
      body: Stack(
        children: [
          MobileScanner(
            controller: controller,
            onDetect: _handleBarcode,
          ),
          // 条形码扫描动画
          QrCodeScanAnimation(),
        ],
      ),
    );
  }
}

  • 具体使用
  • 在父页面,点击扫描按钮后跳转扫描页面,扫描成功后返回数据和销毁扫描页
 InkWell(
            onTap: () {
              Navigator.push(
                  context,
                  MaterialPageRoute(
                      builder: (context) => ScanCode(onScanCompleted: (value) {
                              print(value);
                          })));
            },
            child: Icon(
              Icons.qr_code_scanner,
              color: Theme.of(context).colorScheme.onSurface,
              size: 28,
            ),
          )

到这里,简单的扫码功能就实现了,能够直接扫描二维码和条形码,具体支持哪些格式可自行查看官网。

通过DeepSeek添加扫码动画

  • 基础扫码功能,界面啥的没有,非常简陋,稍微添加一个扫码动画
  • 需求直接抛给 deepseek ,让deepseek帮我们写
image.png
  • deepseek 代码如下:
import 'package:flutter/material.dart';

class QrCodeScanAnimation extends StatefulWidget {
  const QrCodeScanAnimation({super.key});
  @override
  // ignore: library_private_types_in_public_api
  _QrCodeScanAnimation createState() => _QrCodeScanAnimation();
}

class _QrCodeScanAnimation extends State<QrCodeScanAnimation>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: const Duration(seconds: 2),
      vsync: this,
    )..repeat();
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Center(
      child: CustomPaint(
        painter: ScannerPainter(_controller),
        size: Size(250, 250),
      ),
    );
  }
}

class ScannerPainter extends CustomPainter {
  final Animation<double> animation;

  ScannerPainter(this.animation) : super(repaint: animation);

  @override
  void paint(Canvas canvas, Size size) {
    final width = size.width;
    final height = size.height;
    final paintColor = Colors.blue;
    final borderPaint = Paint()
      ..color = paintColor
      ..style = PaintingStyle.stroke
      ..strokeWidth = 3;

    // 绘制四角边框
    final cornerLength = 25.0;

    // 左上角
    canvas.drawLine(Offset.zero, Offset(cornerLength, 0), borderPaint);
    canvas.drawLine(Offset.zero, Offset(0, cornerLength), borderPaint);

    // 右上角
    canvas.drawLine(
        Offset(width, 0), Offset(width - cornerLength, 0), borderPaint);
    canvas.drawLine(Offset(width, 0), Offset(width, cornerLength), borderPaint);

    // 左下角
    canvas.drawLine(
        Offset(0, height), Offset(cornerLength, height), borderPaint);
    canvas.drawLine(
        Offset(0, height), Offset(0, height - cornerLength), borderPaint);

    // 右下角
    canvas.drawLine(Offset(width, height), Offset(width - cornerLength, height),
        borderPaint);
    canvas.drawLine(Offset(width, height), Offset(width, height - cornerLength),
        borderPaint);

    // 绘制扫描线
    final linePaint = Paint()
      ..shader = LinearGradient(
        colors: [Colors.transparent, paintColor, Colors.transparent],
        stops: [0.1, 0.5, 0.9],
      ).createShader(Rect.fromLTWH(0, 0, width, 3))
      ..strokeWidth = 3;

    final lineY = height * animation.value;
    canvas.drawLine(
      Offset(0, lineY),
      Offset(width, lineY),
      linePaint,
    );
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
}

  • 最终效果,四个角有边框包裹,中间有一条扫描线从上到下循环执行,代码复制过来就能用,效果也不错,反正deepseek牛逼就完了。

微信图片_20250220091557.jpg