Flutter实现打印功能的示例详解

这篇文章主要为大家详细介绍了如何通过 Flutter 实现调用打印机打印的功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下

开发环境
Flutter Version:3.16.4
系统:macOS Sonoma - Apple M1 芯片
Android Studio: 17.0.7

我们通过 flutter create project_name 创建项目。

我们如何打印
关于调起 printer 打印的功能。我们有以下的想法:

打印当前路由页面的内容,类似于网页的调用 window.print 方式打印
打印页面中指定的 widget 的内容
打印重组的 widget 的内容
将页面指定的 widget 转化为 image 之后,再调起打印
针对第一点,我们并没有发现在 app 中有类似 window.print 的方法;而对第二点,我们也不能指定页面中 widget 进行打印。剩下的第三点和第四点,我们都可以实现。

接下来,我们将应用 flutter printing 包,来演示后两种实现方式。

引入 printing 包
引入 printing 很简单:

将 printing 包添加到我们的 pubspec.yaml 文件:

dependencies:
  flutter:
    sdk: flutter
  webview_flutter: ^2.0.13 # optional
  flutter_inappwebview: ^5.3.2 # optional
 
  # The following adds the Cupertino Icons font to your application.
  # Use with the CupertinoIcons class for iOS style icons.
  cupertino_icons: ^1.0.2
  printing: ^5.12.0

webview_flutter 和 flutter_inappwebview 是可选,笔者在调试 macos 的项目时候用到。printing 在编写本文时候的版本是 ^5.12.0,请以 官网 版本为主

然后,我们可以通过 flutter pub get 来获取包

打印组合的 widgets
下面,我们以一个简单的案例来说说怎么使用该包,并怎么打印组合的 widget。

我们直接在项目的 main.dart 上操作:

import 'package:pdf/pdf.dart';
import 'package:pdf/widgets.dart' as pw;
import 'package:printing/printing.dart';

上面引入 pdf 和 printing 相关包。

因为我们是在 macos 上进行调试,我们还需要在 macos/Runner/Release.entitlements 和 macos/Runner/DebugProfile.entitlements 文件中添加内容:

<key>com.apple.security.print</key>
<true/>

如果是其他平台开发调试,请参考 printing 引入相关的内容。

之后我们在 main.dart 中实现相关的逻辑:

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: Text('Print Demo'),
    ),
    body: Center(
      child: ElevatedButton(
        onPressed: _printPdf,
        child: Text('Print'),
      ),
    ),
  );
}

上面我们编写了相关的 widget,展示一个 Print 按钮,当点击按钮时候,触发方法 _printPdf,该方法的实现如下

Future<void> _printPdf() async {
  try {
    final doc = pw.Document();
     
    doc.addPage(pw.Page(
      pageFormat: PdfPageFormat.a4,
      build: (pw.Context context) {
        return pw.Center(
          child: pw.Text('Hello Jimmy'),
        );
      }
    ));
     
    await Printing.layoutPdf(  
      onLayout: (PdfPageFormat format) async => doc.save(),  
    );
  } catch (e) {
    print(e);
  } 
}

在这个方法中,我们在 addPage 中重新组合了需要打印的 widgets,然后调起打印机 Printing.layoutPdf,动态如下

那么,对于复杂的内容,如果我们还是编写自定义的 widgets 的话,那不切实际,维护成本高。那么,我们有什么方法打印它呢?这就是下面我们要介绍的了~

widgets 内容转 image,再打印 image
我们直接将页面上的 widgets 内容转换为 image,再结合上面提及的打印组合的 widgets 处理即可。

将 widgets 内容转 image
先上代码:

import 'dart:typed_data';
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
 
class _MyHomePageState extends State<MyHomePage> {
  final GlobalKey boundaryKey = GlobalKey();
  Uint8List _imageBytes = Uint8List(0);
 
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Widget to Image Demo'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            RepaintBoundary(
              key: boundaryKey,
              child: Container(
                width: 200,
                height: 200,
                color: Colors.blue,
                child: Center(
                  child: Text(
                    'Hello, Jimmy!',
                    style: TextStyle(
                      color: Colors.white,
                      fontSize: 24,
                    ),
                  ),
                ),
              ),
            ),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: _capturePng,
              child: Text('Capture Image'),
            ),
            SizedBox(height: 20),
            if (!_imageBytes.isEmpty)
              Image.memory(
                _imageBytes,
                width: 200,
                height: 200,
              ),
          ],
        ),
      ),
    );
  }
 
  Future<void> _capturePng() async {
    try {
      RenderRepaintBoundary? boundary =
      boundaryKey.currentContext?.findRenderObject() as RenderRepaintBoundary?;
      ui.Image? image = await boundary?.toImage(pixelRatio: 3.0);
      ByteData? byteData =
      await image?.toByteData(format: ui.ImageByteFormat.png);
      setState(() {
        _imageBytes = byteData!.buffer.asUint8List(); // 赋值
      });
    } catch (e) {
      print(e);
    }
  }
}

在代码中,我们用 RepaintBoundary 来指定了重绘的区域为 200*200 的文本值。当我们点击 ElevatedButton 挂件时候,会触发 _capturePng 方法。在 _capturePng 方法中,我们将区域内的内容转换为图像,并且,将图像转为位数据,给 _imageBytes 赋值,展现在页面上。相关 Gif 图如下

整合 Image 挂件
在上面的例子中,我们保存了生成的图数据。接下来,我们将该图片打印出来。上面的代码,我们在原始基础上更改:

ElevatedButton(
  onPressed: () => _capturePng(context),
  child: Text('Capture Image'),
),

引入包:

import 'package:pdf/pdf.dart';
import 'package:pdf/widgets.dart' as pw;
import 'package:printing/printing.dart';

然后补充 _capturePng 方法:

Future<void> _capturePng(BuildContext ctx) async {
  try {
    // 添加 print
    final doc = pw.Document();
 
    RenderRepaintBoundary? boundary = boundaryKey.currentContext
      ?.findRenderObject() as RenderRepaintBoundary?;
    ui.Image? image = await boundary?.toImage(pixelRatio: 3.0);
    ByteData? byteData =
      await image?.toByteData(format: ui.ImageByteFormat.png);
 
    final pageFormat = PdfPageFormat.a4;
   
    print(MediaQuery.of(ctx).size.height); // 测试打印界面的高度
 
    doc.addPage(pw.Page(
      pageFormat: pageFormat,
      orientation: pw.PageOrientation.landscape,
      build: (pw.Context context) {
        return pw.Center(
          child: pw.Image( // 图像挂件
            pw.MemoryImage(_imageBytes),
            width: pageFormat.height - 20,
            fit: pw.BoxFit.fitWidth,
          ),
        );
      }));
 
    // 打印
    await Printing.layoutPdf(
      onLayout: (PdfPageFormat format) async => doc.save(),
    );
  } catch (e) {
    print(e);
  }
}

上面,我们通过 pw.MemoryImage(_imageBytes) 指定 Image 的内容,并调起打印机打印~

为了方便演示,看到边界,我们更改了下 UI

当然,我们可以设定其打印的边距和指定内容的方向等:

pw.Page(
  orientation: pw.PageOrientation.landscape, // 内容的方向
  margin: pw.EdgeInsets.all(16.0), // 边距
  ...
)

LESS 复制 全屏

以上就是Flutter实现打印功能的示例详解的详细内容,更多关于Flutter打印的资料请关注vb.net教程C#教程python教程SQL教程access 2010教程xin3721自学网

Flutter 支持通过蓝牙打印机进行打印。你可以使用插件 `flutter_bluetooth_serial` 来实现蓝牙打印功能。下面是一个简单的示例: 首先,在 `pubspec.yaml` 文件中添加如下依赖: ```yaml dependencies: flutter_bluetooth_serial: ^0.0.9 ``` 然后,在需要使用蓝牙打印功能的页面中,引入插件: ```dart import 'package:flutter_bluetooth_serial/flutter_bluetooth_serial.dart'; ``` 接下来,你需要使用 `FlutterBluetoothSerial` 类中的方法来搜索蓝牙设备并连接到你想要连接的设备。以下是一个搜索并连接到蓝牙设备的示例代码: ```dart // 搜索蓝牙设备 List<BluetoothDevice> devices = []; bool isSearching = true; FlutterBluetoothSerial.instance.startDiscovery().listen((device) { setState(() { devices.add(device); }); }); // 连接到设备 BluetoothConnection connection; Future<void> _connectToDevice(BluetoothDevice device) async { BluetoothConnection.toAddress(device.address).then((_connection) { print('已连接到设备 ${device.name}'); setState(() { connection = _connection; isSearching = false; }); }).catchError((error) { print('连接错误: $error'); }); } ``` 连接成功后,你可以使用 `BluetoothConnection` 对象中的 `output` 属性来写入数据并打印。以下是一个打印文本的示例代码: ```dart void _printText() { connection.output.add(utf8.encode('Hello Bluetooth Printer!\n')); connection.output.allSent.then((_) { print('打印完成'); }); } ``` 当然,打印不仅仅是打印文本,具体的打印格式需要根据你连接的打印机类型而定,你需要查看打印机的开发文档来了解具体的打印格式和指令。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值