flutter开发实战-flutter二维码条形码扫一扫功能实现

flutter开发实战-flutter二维码扫一扫功能实现,要使用到摄像头的原生的功能,使用的是插件:scan

效果图如下

在这里插入图片描述

一、扫一扫插件scan

  # 扫一扫
  scan: ^1.6.0

1.1 iOS权限设置

<key>NSCameraUsageDescription</key>
<string>Your Description</string>

<key>io.flutter.embedded_views_preview</key>
<string>YES</string>

1.2 android权限设置

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

<application>
  <meta-data
    android:name="flutterEmbedding"
    android:value="2" />
</application>

1.3 使用ScanView的widget

ScanController controller = ScanController();
String qrcode = 'Unknown';

Container(
  width: 250, // custom wrap size
  height: 250,
  child: ScanView(
    controller: controller,
// custom scan area, if set to 1.0, will scan full area
    scanAreaScale: .7,
    scanLineColor: Colors.green.shade400,
    onCapture: (data) {
      // do something
    },
  ),
),

扫一扫Widget使用ScanController来做响应的控制

暂停/恢复camera

controller.pause();
controller.resume();

识别图片的二维码结果

String result = await Scan.parse(imagePath);

闪光灯切换

controller.toggleTorchMode();

二、代码实现

实现自定义扫码的appBar

class QrScanAppBar extends StatefulWidget {
  const QrScanAppBar({
    Key? key,
    required this.toolbarHeight,
    this.elevation,
    this.backgroundColor,
    this.leadingWidget,
    this.trailingWidget,
    this.centerWidget,
    this.brightness,
    this.padding, this.barPadding,
  }) : super(key: key);

  final double toolbarHeight;
  final double? elevation;
  final Color? backgroundColor;
  final Widget? leadingWidget;
  final Widget? trailingWidget;
  final Widget? centerWidget;
  final Brightness? brightness;
  final EdgeInsetsGeometry? padding;
  final EdgeInsetsGeometry? barPadding;

  
  State<QrScanAppBar> createState() => _QrScanAppBarState();
}

class _QrScanAppBarState extends State<QrScanAppBar> {
  
  Widget build(BuildContext context) {
    final SystemUiOverlayStyle overlayStyle =
        widget.brightness == Brightness.dark
            ? SystemUiOverlayStyle.light
            : SystemUiOverlayStyle.dark;

    Widget leadingWidget = (widget.leadingWidget ?? Container());
    Widget centerWidget = (widget.centerWidget ?? Container());
    Widget trailingWidget = (widget.trailingWidget ?? Container());

    return AnnotatedRegion<SystemUiOverlayStyle>(
      //套AnnotatedRegion是为了增加状态栏控制
      value: overlayStyle,
      child: Material(
        //套Material是为了增加elevation
        elevation: widget.elevation ?? 0,
        color: Colors.transparent,
        child: Container(
          padding: widget.padding,
          height: widget.toolbarHeight + ScreenUtil().statusBarHeight,
          decoration: BoxDecoration(
            color: widget.backgroundColor,
          ),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [
              Container(
                height: ScreenUtil().statusBarHeight,
              ),
              Expanded(
                child: Container(
                  padding: widget.barPadding,
                  height: widget.toolbarHeight,
                  alignment: Alignment.center,
                  child: Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    crossAxisAlignment: CrossAxisAlignment.center,
                    children: [
                      Container(
                        height: widget.toolbarHeight,
                        child: leadingWidget,
                      ),
                      Expanded(
                        child: Container(
                          alignment: Alignment.center,
                          height: widget.toolbarHeight,
                          child: centerWidget,
                        ),
                      ),
                      Container(
                        height: widget.toolbarHeight,
                        child: trailingWidget,
                      ),
                    ],
                  ),
                ),
              )
            ],
          ),
        ),
      ),
    );
  }
}

实现扫一扫界面

class QrScanPage extends StatefulWidget {
  const QrScanPage({Key? key, this.arguments}) : super(key: key);

  final Object? arguments;

  
  State<QrScanPage> createState() => _QrScanPageState();
}

class _QrScanPageState extends State<QrScanPage> {
  ScanController scanController = ScanController();
  String qrcode = 'Unknown';
  bool torchOn = false;

  
  void initState() {
    // TODO: implement initState
    super.initState();
  }

  
  void dispose() {
    // TODO: implement dispose
    scanController.pause();
    super.dispose();
  }

  void changedTorchMode() {
    scanController.toggleTorchMode();
    if (torchOn == true) {
      torchOn = false;
    } else {
      torchOn = true;
    }
    setState(() {});
  }

  void refreshScan() {
    scanController.resume();
  }

  // controller.resume();
  // controller.pause();
  // String result = await Scan.parse(imagePath);

  
  Widget build(BuildContext context) {
    return Scaffold(
      body: Stack(
        children: [
          buildQrScanView(context),
          Positioned(
            child: buildAppBar(context),
          ),
        ],
      ),
    );
  }

  Widget buildQrScanView(BuildContext context) {
    double width = MediaQuery.of(context).size.width;
    double height = MediaQuery.of(context).size.height;

    double scanW = width * 0.75;
    double scanMY = (height - scanW) / 2.0 + scanW + 15.0;

    return Container(
          alignment: Alignment.center,
          child: Stack(
            alignment: Alignment.center,
            children: [
              ScanView(
                controller: scanController,
                // custom scan area, if set to 1.0, will scan full area
                scanAreaScale: 0.75,
                scanLineColor: Colors.green.shade400,
                onCapture: (data) {
                  // do something
                  LoggerManager().debug("onCapture:${data}");
                  openQrScanWebPage(data);
                },
              ),
              Positioned(
                top: scanMY,
                child: buildOption(context, scanMY),
              ),
            ],
          ),
        );
  }

  Widget buildAppBar(BuildContext context) {
    return QrScanAppBar(
      toolbarHeight: 44.0,
      backgroundColor: Colors.transparent,
      padding: EdgeInsets.symmetric(horizontal: 10.0),
      barPadding: EdgeInsets.symmetric(vertical: 4.0),
      leadingWidget: Container(
        alignment: Alignment.center,
        child: QrscanButton(
          bgColor: ColorUtil.hexColor(0xA9A9A9),
          bgHighlightedColor: ColorUtil.hexColor(0xf0f0f0),
          borderColor: Colors.transparent,
          onPressed: () {
            navigatorBack();
          },
          borderRadius: 18.0,
          height: 36.0,
          width: 36.0,
          child: ImageHelper.wrapAssetAtImages(
            "icons/ic_scan_navback.png",
            width: 36.0,
            height: 36.0,
            fit: BoxFit.fill,
          ),
        ),
      ),
      centerWidget: Text(
        S.of(context).qrScan,
        textAlign: TextAlign.center,
        softWrap: true,
        style: TextStyle(
          fontSize: 17,
          color: ColorUtil.hexColor(0xffffff),
          fontWeight: FontWeight.w600,
          fontStyle: FontStyle.normal,
          decoration: TextDecoration.none,
        ),
      ),
      trailingWidget: Container(
        width: 32.0,
        height: 32.0,
      ),
    );
  }

  Widget buildOption(BuildContext context, double originY) {
    return Container(
      height: ScreenUtil().screenHeight - originY,
      width: ScreenUtil().screenWidth,
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          Container(
            width: 300.0,
            child: Text(
              S.of(context).qrScanBottomTip,
              textAlign: TextAlign.center,
              softWrap: true,
              style: TextStyle(
                fontSize: 15,
                fontWeight: FontWeight.w500,
                fontStyle: FontStyle.normal,
                color: Colors.white,
                decoration: TextDecoration.none,
              ),
            ),
          ),
          SizedBox(
            height: 25.0,
          ),
          buildButtons(context),
          Expanded(
            child: Container(),
          ),
        ],
      ),
    );
  }

  Widget buildButtons(BuildContext context) {
    return Row(
      mainAxisAlignment: MainAxisAlignment.center,
      crossAxisAlignment: CrossAxisAlignment.center,
      children: [
        Padding(
          padding: EdgeInsets.symmetric(horizontal: 20.0),
          child: QrscanButton(
            bgColor: ColorUtil.hexColor(0x35fb99),
            bgHighlightedColor: Colors.green.shade400,
            onPressed: () {
              changedTorchMode();
            },
            width: 100.0,
            height: 50.0,
            borderRadius: 25.0,
            child: Text(
              (torchOn
                  ? S.of(context).qrScanTorchOff
                  : S.of(context).qrScanTorchOn),
              textAlign: TextAlign.center,
              softWrap: true,
              style: TextStyle(
                fontSize: 14,
                color: ColorUtil.hexColor(0xffffff),
                fontWeight: FontWeight.w600,
                fontStyle: FontStyle.normal,
                decoration: TextDecoration.none,
              ),
            ),
          ),
        ),
        Padding(
          padding: EdgeInsets.symmetric(horizontal: 20.0),
          child: QrscanButton(
            bgColor: ColorUtil.hexColor(0x35fb99),
            bgHighlightedColor: Colors.green.shade400,
            onPressed: () {
              refreshScan();
            },
            width: 100.0,
            height: 50.0,
            borderRadius: 25.0,
            child: Text(
              S.of(context).qrScanRefresh,
              textAlign: TextAlign.center,
              softWrap: true,
              style: TextStyle(
                fontSize: 14,
                color: ColorUtil.hexColor(0xffffff),
                fontWeight: FontWeight.w600,
                fontStyle: FontStyle.normal,
                decoration: TextDecoration.none,
              ),
            ),
          ),
        ),
      ],
    );
  }

  void navigatorBack() {
    NavigatorPageRouter.pop();
  }

  void openQrScanWebPage(String data) {
    Map<String, dynamic> args = {};
    args["url"] = data;

    /// true保留跳转的当前栈   false 不保留
    NavigatorPageRouter.pushReplacementNamed(
      RouterName.web,
      arguments: args,
    );
  }
}

三、小结

flutter开发实战-flutter二维码扫一扫功能实现,要使用到摄像头的原生的功能,使用的是插件:scan,实现自定义Appbar。

学习记录,每天不停进步。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐