基于Flutter实现扫描二维码功能

 更新时间:2024年11月21日 15:40:25   作者:fifiAmx  
在今天的移动开发中,二维码扫描已经成为了常见的功能之一,Flutter作为一款跨平台的开发框架,提供了丰富的插件和功能,下面我们就来看看如何使用Flutter实现扫描二维码功能吧

在今天的移动开发中,二维码扫描已经成为了常见的功能之一。Flutter作为一款跨平台的开发框架,提供了丰富的插件和功能,使得开发者可以轻松实现二维码扫描以及图像识别功能。本文将介绍如何在Flutter中通过结合 scan 插件、permission_handler 插件以及 image_picker 插件,实现二维码扫描和从相册选择二维码图片的功能。

效果图

1、相机扫描二维码

2、相册选择二维码并扫描

1、项目依赖

首先,我们需要在 pubspec.yaml 文件中添加以下依赖:

dependencies:
  flutter:
    sdk: flutter
  scan: ^1.6.0          # 用于扫描二维码
  permission_handler: ^10.2.0  # 用于权限请求
  image_picker: ^1.0.7    # 用于从相册选择图片

这些插件的作用如下:

scan:提供二维码扫描功能。

permission_handler:用于请求相机权限,确保用户授权后才能使用相机进行二维码扫描。

image_picker:允许从相册选择图片,便于用户上传二维码图片进行识别。

2、配置权限

在 Android 平台上,为了使用相机功能,需要在 AndroidManifest.xml 文件中添加必要的权限:

<uses-permission android:name="android.permission.CAMERA"/>

在 IOS平台上修改 Info.plist 文件,打开 ios/Runner/Info.plist 文件,确保添加以下配置(iOS用虚拟机是调试不了的,实测打不开相机):

<key>NSCameraUsageDescription</key>
<string>需要访问相机用于二维码扫描</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>需要访问相册选择图片</string>

3、实现二维码扫描功能

接下来,我们来看看如何实现二维码扫描功能。我们需要创建一个主界面,在其中添加按钮来请求相机权限,并进行二维码扫描。

没有二维码的小伙伴可以查看上一篇文章:Flutter 生成二维码

import 'package:flutter/material.dart';
import 'package:scan/scan.dart';  // 导入 scan 插件
import 'package:permission_handler/permission_handler.dart';  // 导入权限请求插件
import 'package:image_picker/image_picker.dart';  // 导入相册选择插件
 
void main() {
  runApp(MyApp());
}
 
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: QRScannerScreen(),
    );
  }
}
 
class QRScannerScreen extends StatefulWidget {
  @override
  _QRScannerScreenState createState() => _QRScannerScreenState();
}
 
class _QRScannerScreenState extends State<QRScannerScreen> {
  ScanController controller = ScanController();  // 创建扫描控制器
  String qrcode = 'Unknown';  // 默认二维码内容
 
  // 执行二维码扫描前请求权限
  _requestPermissions() async {
    var cameraStatus = await Permission.camera.request();
    if (cameraStatus.isGranted) {
      // 权限已授予,开始扫描
      print("相机权限已授予,开始扫描");
      // 点击按钮后跳转到全屏扫描界面
      Navigator.push(
        context,
        MaterialPageRoute(builder: (context) => QRScanPage(controller: controller)),
      ).then((result) {
        controller.pause();  // 暂停扫描
        // 扫描完成后获取返回的二维码数据并更新显示
        if (result != null) {
          setState(() {
            qrcode = result;  // 更新二维码内容
          });
        }
      });
    } else {
      // 权限被拒绝或未授权
      print("相机权限未授予,请授权");
      // 可以引导用户去设置页面
    }
  }
 
  // 选择相册中的二维码图片
  _selectImageFromGallery() async {
    final picker = ImagePicker();
    final pickedFile = await picker.pickImage(source: ImageSource.gallery);
    if (pickedFile != null) {
      String result = await Scan.parse(pickedFile.path) ?? '';  // 解析选中的图片
      setState(() {
        qrcode = result;  // 更新二维码内容
      });
    }
  }
 
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('二维码扫描器'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            // 显示二维码扫描结果
            const Text(
              '二维码扫描结果:',
              style: TextStyle(fontSize: 18),
            ),
            const SizedBox(height: 10),
            Text(
              qrcode,
              style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
            ),
            const SizedBox(height: 30),
            // 扫描按钮
            ElevatedButton(
              onPressed: _requestPermissions,  // 执行权限请求
              child: const Text('请求权限并开始扫描'),
            ),
            const SizedBox(height: 30),
            // 选择相册按钮
            ElevatedButton(
              onPressed: _selectImageFromGallery,  // 选择相册
              child: const Text('从相册选择二维码图片'),
            ),
          ],
        ),
      ),
    );
  }
}

代码解释

权限请求:我们通过 permission_handler 插件请求相机权限。用户允许后才能进行二维码扫描。

扫描功能:我们使用 ScanController 来控制扫描过程。点击按钮后,跳转到全屏扫描页面 QRScanPage,在该页面,用户可以通过相机扫描二维码。

从相册选择图片:我们利用 image_picker 插件允许用户从相册选择图片,并解析二维码。

4、全屏扫描页面

当用户点击扫描按钮时,应用会进入一个全屏扫描页面。在该页面中,二维码扫描功能全屏展示,并且添加了一个“选择相册”按钮,让用户可以在扫描时直接选择图片。

class QRScanPage extends StatelessWidget {
  final ScanController controller;
  const QRScanPage({super.key, required this.controller});
 
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('扫描二维码')),
      body: Stack(
        alignment: Alignment.center,
        children: [
          // 使用 ScanView 进行全屏扫描
          ScanView(
            controller: controller,
            scanAreaScale: 0.8,  // 设置扫描区域占满整个屏幕
            scanLineColor: Colors.green.shade400,  // 设置扫描线颜色
            onCapture: (data) {
              // 扫描到二维码后,返回数据
              controller.pause();  // 暂停扫描
              Navigator.pop(context, data);  // 返回扫描结果
            },
          ),
          // 在屏幕上添加选择相册按钮
          Positioned(
            bottom: 100,
            child: ElevatedButton(
              onPressed: () async {
                // 选择相册
                final picker = ImagePicker();
                final pickedFile = await picker.pickImage(source: ImageSource.gallery);
                if (pickedFile != null) {
                  String result = await Scan.parse(pickedFile.path) ?? '';  // 解析选中的图片
                  Navigator.pop(context, result);  // 返回二维码结果
                }
              },
              child: const Text(
                '选择相册',
                style: TextStyle(
                  fontSize: 18,
                  color: Colors.white,
                  fontWeight: FontWeight.bold,
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

代码解释

ScanView:提供扫描界面,支持自定义扫描区域和扫描线颜色。

onCapture:当扫描到二维码时,会返回扫描结果并暂停扫描。

选择相册按钮:点击按钮可以让用户从相册选择二维码图片进行解析。

完整demo

可以直接复制到新项目跑起来

import 'package:flutter/material.dart';
import 'package:scan/scan.dart';  // 导入 scan 插件
import 'package:permission_handler/permission_handler.dart';  // 导入权限请求插件
import 'package:image_picker/image_picker.dart';  // 导入相册选择插件
 
void main() {
  runApp(MyApp());
}
 
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: QRScannerScreen(),
    );
  }
}
 
class QRScannerScreen extends StatefulWidget {
  @override
  _QRScannerScreenState createState() => _QRScannerScreenState();
}
 
class _QRScannerScreenState extends State<QRScannerScreen> {
  ScanController controller = ScanController();  // 创建扫描控制器
  String qrcode = 'Unknown';  // 默认二维码内容
 
  // 执行二维码扫描前请求权限
  _requestPermissions() async {
    var cameraStatus = await Permission.camera.request();
    if (cameraStatus.isGranted) {
      // 权限已授予,开始扫描
      print("相机权限已授予,开始扫描");
      // 点击按钮后跳转到全屏扫描界面
      Navigator.push(
        context,
        MaterialPageRoute(builder: (context) => QRScanPage(controller: controller)),
      ).then((result) {
        controller.pause();  // 暂停扫描
        // 扫描完成后获取返回的二维码数据并更新显示
        if (result != null) {
          setState(() {
            qrcode = result;  // 更新二维码内容
          });
        }
      });
    } else {
      // 权限被拒绝或未授权
      print("相机权限未授予,请授权");
      // 可以引导用户去设置页面
    }
  }
 
  // 选择相册中的二维码图片
  _selectImageFromGallery() async {
    final picker = ImagePicker();
    final pickedFile = await picker.pickImage(source: ImageSource.gallery);
    if (pickedFile != null) {
      String result = await Scan.parse(pickedFile.path) ?? '';  // 解析选中的图片
      setState(() {
        qrcode = result;  // 更新二维码内容
      });
    }
  }
 
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('二维码扫描器'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            // 显示二维码扫描结果
            const Text(
              '二维码扫描结果:',
              style: TextStyle(fontSize: 18),
            ),
            const SizedBox(height: 10),
            Text(
              qrcode,
              style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
            ),
            const SizedBox(height: 30),
            // 扫描按钮
            ElevatedButton(
              onPressed: _requestPermissions,  // 执行权限请求
              child: const Text('请求权限并开始扫描'),
            ),
            const SizedBox(height: 30),
            // 选择相册按钮
            ElevatedButton(
              onPressed: _selectImageFromGallery,  // 选择相册
              child: const Text('从相册选择二维码图片'),
            ),
          ],
        ),
      ),
    );
  }
}
 
class QRScanPage extends StatelessWidget {
  final ScanController controller;
  const QRScanPage({super.key, required this.controller});
 
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('扫描二维码')),
      body: Stack(
        alignment: Alignment.center,
        children: [
          // 使用 ScanView 进行全屏扫描
          ScanView(
            controller: controller,
            scanAreaScale: 0.8,  // 设置扫描区域占满整个屏幕
            scanLineColor: Colors.green.shade400,  // 设置扫描线颜色
            onCapture: (data) {
              // 扫描到二维码后,返回数据
              controller.pause();  // 暂停扫描
              Navigator.pop(context, data);  // 返回扫描结果
            },
          ),
          // 在屏幕上添加选择相册按钮
          Positioned(
            bottom: 100,
            child: ElevatedButton(
              onPressed: () async {
                // 选择相册
                final picker = ImagePicker();
                final pickedFile = await picker.pickImage(source: ImageSource.gallery);
                if (pickedFile != null) {
                  String result = await Scan.parse(pickedFile.path) ?? '';  // 解析选中的图片
                  Navigator.pop(context, result);  // 返回二维码结果
                }
              },
              child: const Text(
                '选择相册',
                style: TextStyle(
                  fontSize: 18,
                  color: Colors.white,
                  fontWeight: FontWeight.bold,
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

总结

本文展示了如何在 Flutter 中实现二维码扫描和从相册选择二维码图片的功能。通过使用 scan、permission_handler 和 image_picker 插件,我们可以轻松地添加二维码扫描和图片识别功能。在开发实际应用时,可能还需要处理更多细节,例如处理不同平台的权限请求、优化扫描体验等。

到此这篇关于基于Flutter实现扫描二维码功能的文章就介绍到这了,更多相关Flutter扫描二维码内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • android创建数据库(SQLite)保存图片示例

    android创建数据库(SQLite)保存图片示例

    这篇文章主要介绍了android创建数据库,保存图片到数据库再从数据库取图片的方法,大家参考使用吧
    2014-01-01
  • Android之事件分发机制与冲突详解

    Android之事件分发机制与冲突详解

    这篇文章主要介绍了Android之事件分发机制与冲突详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-09-09
  • Android集成支付宝支付功能示例

    Android集成支付宝支付功能示例

    本篇文章主要介绍了Android集成支付宝支付功能示例,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-07-07
  • Android实现单行标签流式布局

    Android实现单行标签流式布局

    这篇文章主要为大家详细介绍了Android单行标签流式布局,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-09-09
  • Android利用Camera实现中轴3D卡牌翻转效果

    Android利用Camera实现中轴3D卡牌翻转效果

    这篇文章主要介绍了Android利用Camera实现中轴3D卡牌翻转效果,需要的朋友可以参考下
    2015-12-12
  • Android 源码浅析RecyclerView ItemAnimator

    Android 源码浅析RecyclerView ItemAnimator

    这篇文章主要为大家介绍了Android 源码浅析RecyclerView ItemAnimator,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-12-12
  • Android中自定义ImageView添加文字说明详解

    Android中自定义ImageView添加文字说明详解

    Android中的ImageView只能显示矩形的图片,为了用户体验更多,下面这篇文章主要给大家介绍了关于Android中自定义ImageView实现添加文字说明的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴,下面来一起看看吧。
    2017-08-08
  • Android编程设计模式之解释器模式详解

    Android编程设计模式之解释器模式详解

    这篇文章主要介绍了Android编程设计模式之解释器模式,详细分析了Android解释器模式的概念、原理、使用场景、使用方法及相关操作注意事项,需要的朋友可以参考下
    2017-12-12
  • Android5.0以上版本录屏实现代码(完整代码)

    Android5.0以上版本录屏实现代码(完整代码)

    这篇文章主要介绍了Android5.0以上版本录屏实现代码,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2018-01-01
  • 浅析SVN在Android Studio中的安装和配置方法

    浅析SVN在Android Studio中的安装和配置方法

    这篇文章主要介绍了SVN在Android Studio中的安装和配置方法,本文通过图文并茂给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-03-03

最新评论