Flutter二维码扫描插件zxing_scanner的使用

发布于 1周前 作者 eggper 来自 Flutter

Flutter二维码扫描插件zxing_scanner的使用

ZXing Scanner(Dart)

pub package

这是一个可以嵌入到Flutter应用中的条形码扫描组件。它在所有平台上都使用了zxing-dart。

ZXing Dart ZXing Widget ZXing Scanner
pub package pub package pub package

Features

  • ✅ 从摄像头扫描(支持Android、iOS、Web)*
  • ✅ 从图像文件扫描

注意: 从摄像头扫描需要平台支持摄像头功能。目前摄像头插件支持Android、iOS和Web。在某些移动设备浏览器上获取摄像头时可能会出现错误,详见 camera fix for web

Getting started

flutter pub add zxing_scanner

Usage

从摄像头扫描

ScanView(
  onResult: (List<Result> results),
)

从图像文件扫描

List<Result> results = await scanImage(await file.readAsBytes());

Additional information

此包依赖于 zxing_lib,这是一个纯Dart版本的ZXing库。

示例代码

以下是一个完整的示例代码,展示了如何使用zxing_scanner插件从摄像头和图像文件中扫描二维码。

import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:zxing_scanner/zxing_scanner.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Zxing Scanner Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Zxing Scanner Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  ScanController controller = ScanController();

  void _startScan() {
    controller.start();
  }

  void alert(String message) {
    showDialog(
      context: context,
      builder: (context) {
        return AlertDialog(
          content: Text(message),
          actions: [
            ElevatedButton(
              onPressed: () {
                Navigator.of(context).pop();
              },
              child: const Text('OK'),
            )
          ],
        );
      },
    );
  }

  void showResult(List<Result>? results) {
    if (results?.isEmpty ?? true) {
      alert('未识别到二维码');
    } else {
      alert(
        '共识别出${results!.length}个二维码\n${results.map((e) => e.text).join('\n')}',
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: ScanView(
        autoStart: false,
        controller: controller,
        onResult: showResult,
        child: Stack(
          children: [
            Positioned(
              right: 0,
              top: 0,
              child: Padding(
                padding: const EdgeInsets.only(right: 16, top: 16),
                child: GestureDetector(
                  onTap: () async {
                    Feedback.forTap(context);
                    controller.stop();
                    final XFile? image = await ImagePicker()
                        .pickImage(source: ImageSource.gallery);
                    if (image != null) {
                      final results =
                          await scanImage(await image.readAsBytes());
                      showResult(results);
                    }
                  },
                  behavior: HitTestBehavior.opaque,
                  child: const Icon(
                    Icons.image,
                    color: Colors.blue,
                  ),
                ),
              ),
            ),
            Align(
              alignment: Alignment.bottomCenter,
              child: Padding(
                padding: const EdgeInsets.only(bottom: 16.0),
                child: IconButton(
                  style: IconButton.styleFrom(backgroundColor: Colors.white),
                  onPressed: _startScan,
                  icon: const Icon(
                    Icons.camera,
                    color: Colors.blue,
                  ),
                ),
              ),
            )
          ],
        ),
      ),
    );
  }
}

说明

  1. 导入依赖:首先确保在pubspec.yaml文件中添加了zxing_scanner依赖。
  2. 创建扫描控制器:使用ScanController来控制扫描视图的启动和停止。
  3. 显示扫描结果:通过onResult回调函数处理扫描结果,并显示在对话框中。
  4. 从摄像头扫描:点击底部的相机图标启动摄像头扫描。
  5. 从图像文件扫描:点击右上角的图片图标选择图像文件进行扫描。

希望这个示例能帮助你快速上手使用zxing_scanner插件!


更多关于Flutter二维码扫描插件zxing_scanner的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter二维码扫描插件zxing_scanner的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter项目中使用zxing_scanner插件进行二维码扫描的详细代码示例。

1. 添加依赖

首先,在你的pubspec.yaml文件中添加zxing_scanner依赖:

dependencies:
  flutter:
    sdk: flutter
  zxing_scanner: ^3.0.0  # 请检查最新版本号并替换

2. 导入包

在你的Flutter项目的Dart文件中(例如main.dart),导入zxing_scanner包:

import 'package:flutter/material.dart';
import 'package:zxing_scanner/zxing_scanner.dart';
import 'package:zxing_scanner/camera_access.dart';

3. 创建扫描页面

创建一个扫描页面,例如ScanPage,其中包含一个ZXingScannerWidget

class ScanPage extends StatefulWidget {
  @override
  _ScanPageState createState() => _ScanPageState();
}

class _ScanPageState extends State<ScanPage> implements ZXingScannerListener {
  ZXingScanner? _scanner;
  Result? _result;
  bool? _isScanning;

  @override
  void initState() {
    super.initState();
    _scanner = ZXingScanner.builder()
      .setFormats(DefaultFormats)
      .setBeepEnabled(true)
      .setAutoFocus(true)
      .setOrientationLocked(false)
      .setCameraId(0)  // 使用后置摄像头,1为前置摄像头
      .build()..start();
    _isScanning = true;
  }

  @override
  void dispose() {
    _scanner?.stop();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('二维码扫描'),
      ),
      body: _result == null
          ? ZXingScannerPage(
              titles: '扫描二维码/条码',
              showFlash: true,
              androidCameraPermissionOptions: AndroidCameraPermissionOptions(
                title: '摄像头权限',
                message: '该应用需要摄像头权限以扫描二维码。',
                positiveButton: '确定',
                negativeButton: '取消',
              ),
              iosCameraPermissionOptions: IosCameraPermissionOptions(
                message: '该应用需要摄像头权限以扫描二维码。',
              ),
              onCapture: (Result result) {
                // 扫描成功后的处理逻辑
                setState(() {
                  _result = result;
                  _isScanning = false;
                });
                Navigator.of(context).pop(); // 关闭扫描页面
              },
              onScanError: (String errorMessage) {
                print('扫描错误: $errorMessage');
              },
              onCameraError: (String errorMessage, dynamic errorCode) {
                print('摄像头错误: $errorMessage');
              },
              onPermissionDenied: (denied, permanentlyDenied) {
                print('权限被拒绝: $denied, 永久拒绝: $permanentlyDenied');
                if (permanentlyDenied) {
                  showDialog(
                    context: context,
                    builder: (BuildContext context) {
                      return AlertDialog(
                        title: Text('权限被拒绝'),
                        content: Text('您需要授予摄像头权限才能扫描二维码。'),
                        actions: <Widget>[
                          FlatButton(
                            child: Text('打开设置'),
                            onPressed: () {
                              // 引导用户到系统设置
                              CameraAccess.openAppSettings();
                            },
                          ),
                        ],
                      );
                    },
                  );
                }
              },
            )
          : Center(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  Text('扫描结果: ${_result?.text}'),
                  ElevatedButton(
                    onPressed: () {
                      // 重置扫描结果并重新开始扫描
                      setState(() {
                        _result = null;
                        _isScanning = true;
                        _scanner?.start();
                      });
                      Navigator.of(context).popAndPushNamed('/scan');
                    },
                    child: Text('重新扫描'),
                  ),
                ],
              ),
            ),
    );
  }

  @override
  void onScanSuccess(Result result) {
    // 扫描成功时的回调(可选,已在onCapture中处理)
  }

  @override
  void onScanFailed(Exception e) {
    // 扫描失败时的回调
  }

  @override
  void onCameraClosed() {
    // 摄像头关闭时的回调
  }
}

4. 配置路由

在你的路由配置中添加ScanPage,例如在main.dartMaterialApp中:

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      routes: {
        '/': (context) => HomePage(),
        '/scan': (context) => ScanPage(),
      },
    );
  }
}

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('主页'),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            Navigator.of(context).pushNamed('/scan');
          },
          child: Text('开始扫描'),
        ),
      ),
    );
  }
}

5. 运行项目

确保你已经正确配置了Android和iOS的摄像头权限,然后运行你的Flutter项目。你应该能够看到一个按钮,点击后可以进入扫描页面,并扫描二维码或条码。

这样,你就完成了在Flutter项目中使用zxing_scanner插件进行二维码扫描的基本实现。

回到顶部