flutter 2.0 自定义扫一扫

1,142 阅读2分钟

770A5EEFABCEF9F282C8C80EC05D3069.jpg

用到插件

flutter_qr_reader  // 扫码
image_picker  // 图片选择
permission_handler // 权限控制
# 扫码
flutter_qr_reader: ^1.0.5
# 动态鉴权
permission_handler: ^7.1.0
# 图片获取
image_picker: ^0.7.4
#flutter_picker: ^2.0.1

android配置 在/android/src/main/AndroidManifest.xml中

<uses-permission android:name="android.permission.CAMERA" /> <!-- 相机 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <!-- 存储权限 -->

IOS配置 在Info.plist中

<key>io.flutter.embedded_views_preview</key>
<true/>
<key>NSAppleMusicUsageDescription</key>
<string>App需要您的同意,才能访问媒体资料库</string>
<key>NSCameraUsageDescription</key>
<string>App需要您的同意,才能访问相机</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>App需要您的同意,才能访问相册</string>
限 -->

scanPage.dart

import 'package:flutter/material.dart';
import 'dart:async';

import 'package:flutter_qr_reader/flutter_qr_reader.dart';
import 'package:image_picker/image_picker.dart';
import 'package:permission_handler/permission_handler.dart';

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

class _ScanPageState extends State<ScanPage> {
  GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();

  bool flashlightState = false;
  bool showScanView = false;
  bool _openAction = false;
  QrReaderViewController _controller;
  Widget mainUi = Container();

  @override
  void initState() {
    super.initState();
    Future.delayed(Duration(milliseconds: 0)).then((_) async {
      if (false == await permission()) {
        // openAppSettings();
        // Navigator.pop(context);
        return;
      }
      setState(() {
        mainUi = getScanUI();
      });
    });
  }

  // 扫码界面
  Widget getScanUI() {
    return Container(
      child: Stack(
        children: [
          QrReaderView(
            width: MediaQuery.of(context).size.width,
            height: MediaQuery.of(context).size.height,
            callback: (controller) {
              setState(() {
                _controller = controller;
                this.startScan();
              });
            },
          ),
          Container(
            height: 30,
            padding: EdgeInsets.symmetric(horizontal: 30),
            margin: EdgeInsets.only(top: MediaQuery.of(context).padding.top + 20),
            // color: Colors.red,
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                InkWell(
                  onTap: () {
                    Navigator.pop(context);
                  },
                  child: ClipOval(
                    child: Container(
                      width: 24,
                      height: 24,
                      color: Color.fromRGBO(0, 34, 51, 0.25),
                      child: Icon(Icons.clear, color: Colors.white, size: 18),
                    ),
                  ),
                ),
                InkWell(
                  onTap: imgScan,
                  child: Image.asset('assets/images/img_img.png', width: 24),
                ),
              ],
            ),
          ),
          Align(
            child: Container(
              height: MediaQuery.of(context).size.height * 0.8,
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  Container(
                    height: MediaQuery.of(context).size.width * 0.65,
                    width: MediaQuery.of(context).size.width * 0.65,
                    // decoration: BoxDecoration(border: Border.all(width: 1, color: Colors.redAccent)),
                    child: Image.asset('assets/images/scan_frame.png', fit: BoxFit.fitWidth),
                  ),
                  Container(
                    margin: EdgeInsets.only(top: 30),
                    child: InkWell(
                      onTap: flashlight,
                      child: Image.asset('assets/images/icon_light.png', width: 17),
                    ),
                  )
                ],
              ),
            ),
          ),
        ],
      ),
    );
  }

  void alert(String tip) {
    ScaffoldMessenger.of(scaffoldKey.currentContext).showSnackBar(SnackBar(content: Text(tip)));
  }

  // 相机权限dialog
  void showJurisdictionDialog(String text) {
    showDialog(
        context: context,
        builder: (ctx) {
          return AlertDialog(
            title: Text('提示'),
            // content: Text('相机权限没有打开,是否去打开相机权限?'),
            content: Text(text),
            actions: <Widget>[
              TextButton(
                child: Text('取消'),
                onPressed: () {
                  Navigator.pop(context);
                },
              ),
              TextButton(
                child: Text('确认'),
                onPressed: () {
                  openAppSettings(); // 打开权限设置
                },
              ),
            ],
          );
        });
  }

  Future<bool> permission() async {
    if (_openAction) return false;
    _openAction = true;
    var status = await Permission.camera.status;
    // print(status);
    if (status.isDenied || status.isPermanentlyDenied) {
      status = await Permission.camera.request();
      // print(status);
    }

    if (status.isRestricted) {
      // alert("请必须授权照相机权限");
      showJurisdictionDialog("请必须授权照相机权限");
      // await Future.delayed(Duration(seconds: 3));
      openAppSettings();
      _openAction = false;
      return false;
    }

    if (!status.isGranted) {
      // alert("请必须授权照相机权限");
      showJurisdictionDialog("请必须授权照相机权限");
      _openAction = false;
      return false;
    }
    _openAction = false;
    return true;
  }

  // 开始扫码
  Future startScan() async {
    assert(_controller != null);
    _controller?.startCamera((String result, _) async {
      await stopScan();
      debugPrint(result);
      Navigator.pop(context, result);
    });
  }

  // 暂停扫码
  Future stopScan() async {
    assert(_controller != null);
    await _controller?.stopCamera();
    setState(() {
      showScanView = false;
    });
  }

  // 打开手电筒
  Future flashlight() async {
    assert(_controller != null);
    final state = await _controller?.setFlashlight();
    setState(() {
      flashlightState = state ?? false;
    });
  }

  // 选择图片扫码
  Future imgScan() async {
    if (flashlightState) {
      final state = await _controller?.setFlashlight();
      setState(() {
        flashlightState = state ?? false;
      });
    }
    var image = await ImagePicker().getImage(source: ImageSource.gallery);
    if (image == null) return;
    final result = await FlutterQrReader.imgScan(image.path);

    debugPrint(result);
    Navigator.pop(context, result);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: mainUi,
    );
  }
}

调用

// 扫一扫点击
  void onScan() async {
    var result = await Navigator.pushNamed(context, '/scanPage');
    debugPrint('---扫码结果---$result');
  }

图片资源

图一 image.png 图二 image.png 图三 image.png