Wednesday, April 15, 2020

Flutter - Scan and Generate QR Code example

QR and Barcodes are very famous technology that widely used around us. In these codes, you can store information like text, URL, image, and a few other information.

flutter qr and barcode demo
Nowadays, most of the e-commerce companies using this technology to track their product purchase with the help of QR code and Barcode unique IDs. This QR and barcodes can only read by a physical scanner device because these are not humanly readable. 


What is QR Code?

It is a 2-dimensional bar code that stands for Quick Response Code. The QR code can encode over 4000 characters, including punctuation marks and special characters that can be entered in one code by black squares over white background. The encoded content of a QR code cannot be change once generated. The QR codes may be used to display text, contact to the address book  and web site URL as we have encoded www.developerlibs.com in the following QR code: 
qr of www.developerlibs.com
www.developerlibs.com
We can read QR codes with the help of appropriate software installed on the smartphone camera and other QR supported devices. The encoded action will be performed automatically if the code is readable.

What is Barcode?

The Barcode is a square or rectangular image that contains vertical lines with varying widths. It contains full information about products like serial numbers, product numbers, etc. A bar code has five parts: a quiet zone, a start character, data characters, a stop character, and another quiet zone. They are used in retail stores as part of the product purchase process, in warehouses to track inventories, and among many other uses. The smartphones or barcode scanners can read this encoded information of the barcode. Here, we have an example of Barcode that contains www.developerlibs.com text encoded in the following barcode:

barcode of www.developerlibs.com


In this post, our aim to create a QR/Barcode detection and generate QR code in a Flutter Application. By using this application, you can scan any QR/Barcode and encode any message in the QR code. The final output of the application will look like below:





Creating a new Project

1. Create a new project from File ⇒ New Flutter Project with your development IDE.
2. Now, add the plugin qr_flutter and flutter_qr_bar_scanner as a dependency in the pubspec.yaml file. Once you do that, you need to run flutter packages.

3. We have created a class theme.dart that we'll use to design home screen background. So, put the following file in the project directory.
import 'dart:ui';
import 'package:flutter/cupertino.dart';

class Colors {

  const Colors();
  static const Color loginGradientStart = const Color(0xFF02BB9F);
  static const Color loginGradientEnd = const Color(0xFF167F67);

  static const primaryGradient = const LinearGradient(
    colors: const [loginGradientStart, loginGradientEnd],
    stops: const [0.0, 1.0],
    begin: Alignment.topCenter,
    end: Alignment.bottomCenter,
  );
  
}

4. Now, edit main.dart file as we have used  qr_barcode_screen.dart to display QR/Barcode scanner and generator option on one screen:
import 'package:flutter/material.dart';
import 'package:flutterqrbarcode/qr_barcode_screen.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'QR Generator-Scanner',
      home: QRBarcodeScreen(),
    );
  }
}



5. After that create qr_barcode_screen.dart class, where we going to create a widget for QR/Barcode scanner and generate QR code. As we planned to display both features on a single screen. We going to use PageView to displays two widgets on a single screen by providing a slide feature as you can see above video:

Expanded(
                flex: 2,
                child: PageView(
                  controller: _pageController,
                  onPageChanged: (i) {
                    if (i == 0) {
                      setState(() {
                        right = Colors.white;
                        left = Colors.black;
                      });
                    } else if (i == 1) {
                      setState(() {
                        right = Colors.black;
                        left = Colors.white;
                      });
                    }
                  },
                  children: <Widget>[
                    _buildScan(context),
                    _buildGen(context),
                  ],
                ),
              ),

the _buildScan method return widget that shows scanner widget and a Text widget to display scanned value. Here, we have used QRBarScannerCamera widget to create a scanner window of Codes. It has qrCodeCallback method that provides scanned value of codes.

  Widget _buildScan(BuildContext context) {
    return Center(
      child: Card(
          elevation: 2.0,
          color: Colors.white,
          shape: RoundedRectangleBorder(
            borderRadius: BorderRadius.circular(8.0),
          ),
          child: Container(
            padding: const EdgeInsets.all(10.0),
            width: 300,
            height: 500,
            child: Column(
              children: <Widget>[
                Container(
                  height: 300,
                  width: 280,
                  margin: const EdgeInsets.only(bottom: 10),
                  child: QRBarScannerCamera(
                    onError: (context, error) => Text(
                      error.toString(),
                      style: TextStyle(color: Colors.red),
                    ),
                    qrCodeCallback: (code) {
                      _qrCallback(code);
                    },
                  ),
                ),
                Text(
                  _qrInfo,
                  style: TextStyle(color: Colors.black26),
                ),
              ],
            ),
          )),
    );
  }

the _buildGen return a QR code generate widget. It shows generated QR code and Textfield to enter text for generate encoded QR code. 

Widget _buildGen(BuildContext context) {
    final bodyHeight = MediaQuery.of(context).size.height -
        MediaQuery.of(context).viewInsets.bottom;
    return Center(
      child: Card(
        elevation: 2.0,
        color: Colors.white,
        shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.circular(8.0),
        ),
        child: Container(
          width: 300,
          height: 500,
          padding: const EdgeInsets.all(10.0),
          child: Column(
            children: <Widget>[
              Container(
                height: 300,
                width: 280,
                child: RepaintBoundary(
                  key: globalKey,
                  child: QrImage(data: _dataString, size: 0.5 * bodyHeight),
                ),
              ),
              Padding(
                padding: EdgeInsets.only(
                    top: 20.0, bottom: 20.0, left: 25.0, right: 25.0),
                child: TextFormField(
                  focusNode: mFocusNodeQrValue,
                  controller: _textController,
                  textCapitalization: TextCapitalization.words,
                  style: TextStyle(fontSize: 16.0, color: Colors.black),
                  decoration: InputDecoration(
                    hintText: "Enter Text",
                    hintStyle: TextStyle(fontSize: 16.0),
                  ),
                ),
              ),
              _buildGenButton(context),
            ],
          ),
        ),
      ),
    );
  }



the _buildGenButton  refresh QR code widget with latest QR code values:


  Widget _buildGenButton(BuildContext context) {
    return GestureDetector(
        onTap: () {
          setState(() {
            _dataString = _textController.text;
          });
        },
        child: Container(
          width: 150.0,
          height: 50.0,
          decoration: BoxDecoration(
            color: Theme.Colors.loginGradientEnd,
            borderRadius: BorderRadius.all(Radius.circular(25.0)),
          ),
          child: Center(
            child: Icon(
              Icons.refresh,
              color: Colors.white,
            ),
          ),
        ));
  }

the _buildMenuBar display scan and generate slidable buttons.

Widget _buildMenuBar(BuildContext context) {
    return Container(
      width: 300.0,
      height: 50.0,
      decoration: BoxDecoration(
        color: Color(0x552B2B2B),
        borderRadius: BorderRadius.all(Radius.circular(25.0)),
      ),
      child: CustomPaint(
        painter: TabIndicationPainter(pageController: _pageController),
        child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: <Widget>[
            Expanded(
              child: FlatButton(
                splashColor: Colors.transparent,
                highlightColor: Colors.transparent,
                onPressed: _onScanButtonPress,
                child: Text(
                  "Sacn",
                  style: TextStyle(
                    color: left,
                    fontSize: 16.0,
                  ),
                ),
              ),
            ),
            Expanded(
              child: FlatButton(
                splashColor: Colors.transparent,
                highlightColor: Colors.transparent,
                onPressed: _onGenerateButtonPress,
                child: Text(
                  "Generate",
                  style: TextStyle(
                    color: right,
                    fontSize: 16.0,
                  ),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }


here, we have complete code snippet of QR/Barcode Screen:
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:flutter_qr_bar_scanner/qr_bar_scanner_camera.dart';
Flutter QR code scanner demo app
import 'package:qr_flutter/qr_flutter.dart'; import 'bubble_indication_painter.dart'; import 'theme.dart' as Theme; class QRBarcodeScreen extends StatefulWidget { QRBarcodeScreen({Key key}) : super(key: key); @override _QrBarcodeState createState() => new _QrBarcodeState(); } class _QrBarcodeState extends State<QRBarcodeScreen> with SingleTickerProviderStateMixin { final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>(); final FocusNode mFocusNodeQrValue = FocusNode(); TextEditingController qrController = new TextEditingController(); PageController _pageController; Color left = Colors.black; Color right = Colors.white; GlobalKey globalKey = new GlobalKey(); String _dataString = "www.developerlibs.com"; final TextEditingController _textController = TextEditingController();
Flutter QR code generate demo
String _qrInfo = 'Scan a QR/Bar code'; @override Widget build(BuildContext context) { return new Scaffold( key: _scaffoldKey, body: SingleChildScrollView( child: Container( width: MediaQuery.of(context).size.width, height: MediaQuery.of(context).size.height, decoration: new BoxDecoration( gradient: new LinearGradient( colors: [ Theme.Colors.loginGradientStart, Theme.Colors.loginGradientEnd ], begin: const FractionalOffset(0.0, 0.0), end: const FractionalOffset(1.0, 1.0), stops: [0.0, 1.0], tileMode: TileMode.clamp), ), child: Column( mainAxisSize: MainAxisSize.max, children: <Widget>[ Expanded( flex: 2, child: PageView( controller: _pageController, onPageChanged: (i) { if (i == 0) { setState(() { right = Colors.white; left = Colors.black; }); } else if (i == 1) { setState(() { right = Colors.black; left = Colors.white; }); } }, children: <Widget>[ _buildScan(context), _buildGen(context), ], ), ), Padding( padding: EdgeInsets.only(top: 1.0, bottom: 50), child: _buildMenuBar(context), ), ], ), ), ), ); } @override void dispose() { mFocusNodeQrValue.dispose(); _pageController?.dispose(); super.dispose(); } @override void initState() { super.initState(); _pageController = PageController(); } Widget _buildMenuBar(BuildContext context) { return Container( width: 300.0, height: 50.0, decoration: BoxDecoration( color: Color(0x552B2B2B), borderRadius: BorderRadius.all(Radius.circular(25.0)), ), child: CustomPaint( painter: TabIndicationPainter(pageController: _pageController), child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: <Widget>[ Expanded( child: FlatButton( splashColor: Colors.transparent, highlightColor: Colors.transparent, onPressed: _onScanButtonPress, child: Text( "Sacn", style: TextStyle( color: left, fontSize: 16.0, ), ), ), ), //Container(height: 33.0, width: 1.0, color: Colors.white), Expanded( child: FlatButton( splashColor: Colors.transparent, highlightColor: Colors.transparent, onPressed: _onGenerateButtonPress, child: Text( "Generate", style: TextStyle( color: right, fontSize: 16.0, ), ), ), ), ], ), ), ); } Widget _buildGenButton(BuildContext context) { return GestureDetector( onTap: () { setState(() { _dataString = _textController.text; }); }, child: Container( width: 150.0, height: 50.0, decoration: BoxDecoration( color: Theme.Colors.loginGradientEnd, borderRadius: BorderRadius.all(Radius.circular(25.0)), ), child: Center( child: Icon( Icons.refresh, color: Colors.white, ), ), )); } _qrCallback(String code) { setState(() { _qrInfo = code; }); } Widget _buildScan(BuildContext context) { return Center( child: Card( elevation: 2.0, color: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8.0), ), child: Container( padding: const EdgeInsets.all(10.0), width: 300, height: 500, child: Column( children: <Widget>[ Container( height: 300, width: 280, margin: const EdgeInsets.only(bottom: 10), child: QRBarScannerCamera( onError: (context, error) => Text( error.toString(), style: TextStyle(color: Colors.red), ), qrCodeCallback: (code) { _qrCallback(code); }, ), ), Text( _qrInfo, style: TextStyle(color: Colors.black26), ), ], ), )), ); } Widget _buildGen(BuildContext context) { final bodyHeight = MediaQuery.of(context).size.height - MediaQuery.of(context).viewInsets.bottom; return Center( child: Card( elevation: 2.0, color: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8.0), ), child: Container( width: 300, height: 500, padding: const EdgeInsets.all(10.0), child: Column( children: <Widget>[ Container( height: 300, width: 280, child: RepaintBoundary( key: globalKey, child: QrImage(data: _dataString, size: 0.5 * bodyHeight), ), ), Padding( padding: EdgeInsets.only( top: 20.0, bottom: 20.0, left: 25.0, right: 25.0), child: TextFormField( focusNode: mFocusNodeQrValue, controller: _textController, textCapitalization: TextCapitalization.words, style: TextStyle(fontSize: 16.0, color: Colors.black), decoration: InputDecoration( hintText: "Enter Text", hintStyle: TextStyle(fontSize: 16.0), ), ), ), _buildGenButton(context), ], ), ), ), ); } void _onScanButtonPress() { _pageController.animateToPage(0, duration: Duration(milliseconds: 500), curve: Curves.decelerate); } void _onGenerateButtonPress() { _pageController?.animateToPage(1, duration: Duration(milliseconds: 500), curve: Curves.decelerate); } }

You can use source code of this example from below the Github link and you can see the working demo by using Android APK:

flutter qr and barocde source code github               flutter qr and barocde apk android


If you have followed the post carefully, you can see the app running very smoothly as shown in the above video and you able to scan and generate QR code. But if you are facing any problem or you have any quires, please feel free to ask it from comment section.

Share:

We're Social