In this blog post, we will see Generate Dynamic Downloadable QR code for Flutter Web in 2024 using qr_flutter Package.
we’ll walk through a Flutter web application that generates a QR code dynamically based on user input and allows users to download the generated QR code as an image. We’ll use the qr_flutter library for generating QR codes and integrate HTML functionality for downloading the QR code image.
Table of Contents
Prerequisites
Make sure you have the following dependencies in your pubspec.yaml
file:
dependencies:
flutter:
sdk: flutter
qr_flutter: ^4.0.0
Now, let’s dive into the code and understand how it works.
Overview
The Flutter web application consists of a simple user interface with a text input field to enter data and a button to trigger the QR code generation and download process. The QR code is generated using the qr_flutter
library, and the image is downloaded using HTML functionality.
Setting Up the Flutter Web Application
Firstly, create a new Flutter web application and add the required dependencies. Replace the content of your lib/main.dart file with the provided code.
// Import necessary packages and libraries
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:qr_flutter/qr_flutter.dart';
import 'dart:html' as html;
import 'dart:ui' as ui;
void main() {
runApp(const MyApp());
}
// Define the main application widget
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Download QR Code Example',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(title: 'Download QR Code Example'),
);
}
}
// Define the home page widget
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
Implementing QR Code Generation and Download
The _MyHomePageState
class contains the logic for generating and downloading QR codes. The downloadQrCode
function is called when the user clicks the “Download QR Code” button.
class _MyHomePageState extends State<MyHomePage> {
final TextEditingController _textController = TextEditingController();
void downloadQrCode() async {
if (_textController.text.isNotEmpty) {
final qrData = _textController.text;
final qrPainter = QrPainter(
data: qrData,
version: QrVersions.auto,
eyeStyle: const QrEyeStyle(color: Colors.white),
dataModuleStyle: const QrDataModuleStyle(color: Colors.white),
);
final ui.Picture picture = qrPainter.toPicture(300);
final ui.Image image = await picture.toImage(300, 300);
final ByteData? byteData = await image.toByteData(format:ui.ImageByteFormat.png);
final buffer = Uint8List.sublistView(byteData!.buffer.asUint8List());
final blob = html.Blob([buffer]);
final url = html.Url.createObjectUrlFromBlob(blob);
final anchor = html.AnchorElement(href: url)
..target = 'blank'
..download = 'qrcode.png';
html.document.body!.append(anchor);
anchor.click();
html.Url.revokeObjectUrl(url);
} else {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: const Text('Error'),
content: const Text('Please enter text to generate QR code'),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: const Text('OK'),
),
],
);
},
);
}
}
@override
Widget build(BuildContext context) {
// Build the UI components here
}
}
Building the User Interface
Now, let’s complete the build
method to create the user interface with a text input field and a button.
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(
width: 300,
child: TextFormField(
controller: _textController,
decoration: const InputDecoration(
labelText: 'Enter text to generate QR code',
border: OutlineInputBorder(borderRadius: BorderRadius.all(Radius.circular(20))),
),
),
),
const SizedBox(height: 20.0),
TextButton(
style: TextButton.styleFrom(
foregroundColor: Theme.of(context).colorScheme.onPrimary,
backgroundColor: Theme.of(context).colorScheme.primary,
),
onPressed: downloadQrCode,
child: const Text('Download QR Code'),
),
],
),
),
);
}
Demo / Screenshot
Full Code
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:qr_flutter/qr_flutter.dart';
// ignore: avoid_web_libraries_in_flutter
import 'dart:html' as html;
import 'dart:ui' as ui;
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Download QR Code Example',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(title: 'Download QR Code Example'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final TextEditingController _textController = TextEditingController();
void downloadQrCode() async {
setState(() {});
if (_textController.text.isNotEmpty) {
final qrData = _textController.text;
final qrPainter = QrPainter(
data: qrData,
version: QrVersions.auto,
eyeStyle: const QrEyeStyle(color: Colors.white),
dataModuleStyle: const QrDataModuleStyle(color: Colors.white),
);
final ui.Picture picture = qrPainter.toPicture(300);
final ui.Image image = await picture.toImage(300, 300);
final ByteData? byteData = await image.toByteData(format: ui.ImageByteFormat.png);
final buffer = Uint8List.sublistView(byteData!.buffer.asUint8List());
final blob = html.Blob([buffer]);
final url = html.Url.createObjectUrlFromBlob(blob);
final anchor = html.AnchorElement(href: url)
..target = 'blank'
..download = 'qrcode.png';
html.document.body!.append(anchor);
anchor.click();
html.Url.revokeObjectUrl(url);
} else {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: const Text('Error'),
content: const Text('Please enter text to generate QR code'),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: const Text('OK'),
),
],
);
},
);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(
width: 300,
child: TextFormField(
controller: _textController,
decoration: const InputDecoration(
labelText: 'Enter text to generate QR code',
border: OutlineInputBorder(borderRadius: BorderRadius.all(Radius.circular(20))),
),
),
),
const SizedBox(height: 20.0),
TextButton(
style: TextButton.styleFrom(
foregroundColor: Theme.of(context).colorScheme.onPrimary,
backgroundColor: Theme.of(context).colorScheme.primary,
),
onPressed: downloadQrCode,
child: const Text('Download QR Code'),
),
],
),
),
);
}
}