设为首页收藏本站
网站公告 | 这是第一条公告
     

 找回密码
 立即注册
缓存时间23 现在时间23 缓存数据 轻轻的闭上眼睛,慢慢的酝酿心情,将白天所有烦恼不快撒向天空,随着流星的坠落一起沉淀,愿今夜有个好梦,晚安!

轻轻的闭上眼睛,慢慢的酝酿心情,将白天所有烦恼不快撒向天空,随着流星的坠落一起沉淀,愿今夜有个好梦,晚安!

查看: 1913|回复: 4

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

[复制链接]

  离线 

TA的专栏

  • 打卡等级:热心大叔
  • 打卡总天数:204
  • 打卡月天数:0
  • 打卡总奖励:3214
  • 最近打卡:2023-08-27 10:45:29
等级头衔

等級:晓枫资讯-上等兵

在线时间
0 小时

积分成就
威望
0
贡献
416
主题
366
精华
0
金钱
4395
积分
804
注册时间
2022-12-20
最后登录
2025-5-31

发表于 2024-9-11 14:49:49 | 显示全部楼层 |阅读模式
目录


  • 开发环境
  • 我们如何打印
  • 引入 printing 包
  • 打印组合的 widgets
  • widgets 内容转 image,再打印 image

    • 将 widgets 内容转 image
    • 整合 Image 挂件


开发环境


    1. Flutter Version
    复制代码
    :3.16.4
  • 系统:
    1. macOS Sonoma
    复制代码
    -
    1. Apple M1
    复制代码
    芯片
    1. Android Studio
    复制代码
    : 17.0.7
1.webp

我们通过
  1. flutter create project_name
复制代码
创建项目。

我们如何打印

关于调起
  1. printer
复制代码
打印的功能。我们有以下的想法:

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

引入 printing 包

引入 printing 很简单:
  1. printing
复制代码
包添加到我们的
  1. pubspec.yaml
复制代码
文件:
  1. dependencies:
  2.   flutter:
  3.     sdk: flutter
  4.   webview_flutter: ^2.0.13 # optional
  5.   flutter_inappwebview: ^5.3.2 # optional

  6.   # The following adds the Cupertino Icons font to your application.
  7.   # Use with the CupertinoIcons class for iOS style icons.
  8.   cupertino_icons: ^1.0.2
  9.   printing: ^5.12.0
复制代码
  1. webview_flutter
复制代码
  1. flutter_inappwebview
复制代码
是可选,笔者在调试
  1. macos
复制代码
的项目时候用到。
  1. printing
复制代码
在编写本文时候的版本是
  1. ^5.12.0
复制代码
,请以 官网 版本为主
然后,我们可以通过
  1. flutter pub get
复制代码
来获取包

打印组合的 widgets

下面,我们以一个简单的案例来说说怎么使用该包,并怎么打印组合的
  1. widget
复制代码

我们直接在项目的
  1. main.dart
复制代码
上操作:
  1. import 'package:pdf/pdf.dart';
  2. import 'package:pdf/widgets.dart' as pw;
  3. import 'package:printing/printing.dart';
复制代码
上面引入
  1. pdf
复制代码
  1. printing
复制代码
相关包。
因为我们是在
  1. macos
复制代码
上进行调试,我们还需要在
  1. macos/Runner/Release.entitlements
复制代码
  1. macos/Runner/DebugProfile.entitlements
复制代码
文件中添加内容:
  1. <key>com.apple.security.print</key>
  2. <true/>
复制代码
如果是其他平台开发调试,请参考 printing 引入相关的内容。
之后我们在
  1. main.dart
复制代码
中实现相关的逻辑:
  1. @override
  2. Widget build(BuildContext context) {
  3.   return Scaffold(
  4.     appBar: AppBar(
  5.       title: Text('Print Demo'),
  6.     ),
  7.     body: Center(
  8.       child: ElevatedButton(
  9.         onPressed: _printPdf,
  10.         child: Text('Print'),
  11.       ),
  12.     ),
  13.   );
  14. }
复制代码
上面我们编写了相关的
  1. widget
复制代码
,展示一个
  1. Print
复制代码
按钮,当点击按钮时候,触发方法
  1. _printPdf
复制代码
,该方法的实现如下
  1. Future<void> _printPdf() async {
  2.   try {
  3.     final doc = pw.Document();
  4.    
  5.     doc.addPage(pw.Page(
  6.       pageFormat: PdfPageFormat.a4,
  7.       build: (pw.Context context) {
  8.         return pw.Center(
  9.           child: pw.Text('Hello Jimmy'),
  10.         );
  11.       }
  12.     ));
  13.    
  14.     await Printing.layoutPdf(  
  15.       onLayout: (PdfPageFormat format) async => doc.save(),  
  16.     );
  17.   } catch (e) {
  18.     print(e);
  19.   }
  20. }
复制代码
在这个方法中,我们在
  1. addPage
复制代码
中重新组合了需要打印的
  1. widgets
复制代码
,然后调起打印机
  1. Printing.layoutPdf
复制代码
,动态如下
2.webp

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

widgets 内容转 image,再打印 image

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

将 widgets 内容转 image

先上代码:
  1. import 'dart:typed_data';
  2. import 'dart:ui' as ui;
  3. import 'package:flutter/material.dart';
  4. import 'package:flutter/rendering.dart';
  5. import 'package:flutter/services.dart';

  6. class _MyHomePageState extends State<MyHomePage> {
  7.   final GlobalKey boundaryKey = GlobalKey();
  8.   Uint8List _imageBytes = Uint8List(0);

  9.   @override
  10.   Widget build(BuildContext context) {
  11.     return Scaffold(
  12.       appBar: AppBar(
  13.         title: Text('Widget to Image Demo'),
  14.       ),
  15.       body: Center(
  16.         child: Column(
  17.           mainAxisAlignment: MainAxisAlignment.center,
  18.           children: <Widget>[
  19.             RepaintBoundary(
  20.               key: boundaryKey,
  21.               child: Container(
  22.                 width: 200,
  23.                 height: 200,
  24.                 color: Colors.blue,
  25.                 child: Center(
  26.                   child: Text(
  27.                     'Hello, Jimmy!',
  28.                     style: TextStyle(
  29.                       color: Colors.white,
  30.                       fontSize: 24,
  31.                     ),
  32.                   ),
  33.                 ),
  34.               ),
  35.             ),
  36.             SizedBox(height: 20),
  37.             ElevatedButton(
  38.               onPressed: _capturePng,
  39.               child: Text('Capture Image'),
  40.             ),
  41.             SizedBox(height: 20),
  42.             if (!_imageBytes.isEmpty)
  43.               Image.memory(
  44.                 _imageBytes,
  45.                 width: 200,
  46.                 height: 200,
  47.               ),
  48.           ],
  49.         ),
  50.       ),
  51.     );
  52.   }

  53.   Future<void> _capturePng() async {
  54.     try {
  55.       RenderRepaintBoundary? boundary =
  56.       boundaryKey.currentContext?.findRenderObject() as RenderRepaintBoundary?;
  57.       ui.Image? image = await boundary?.toImage(pixelRatio: 3.0);
  58.       ByteData? byteData =
  59.       await image?.toByteData(format: ui.ImageByteFormat.png);
  60.       setState(() {
  61.         _imageBytes = byteData!.buffer.asUint8List(); // 赋值
  62.       });
  63.     } catch (e) {
  64.       print(e);
  65.     }
  66.   }
  67. }
复制代码
在代码中,我们用
  1. RepaintBoundary
复制代码
来指定了重绘的区域为
  1. 200*200
复制代码
的文本值。当我们点击
  1. ElevatedButton
复制代码
挂件时候,会触发
  1. _capturePng
复制代码
方法。在
  1. _capturePng
复制代码
方法中,我们将区域内的内容转换为图像,并且,将图像转为位数据,给
  1. _imageBytes
复制代码
赋值,展现在页面上。相关
  1. Gif
复制代码
图如下
3.webp


整合 Image 挂件

在上面的例子中,我们保存了生成的图数据。接下来,我们将该图片打印出来。上面的代码,我们在原始基础上更改:
  1. ElevatedButton(
  2.   onPressed: () => _capturePng(context),
  3.   child: Text('Capture Image'),
  4. ),
复制代码
引入包:
  1. import 'package:pdf/pdf.dart';
  2. import 'package:pdf/widgets.dart' as pw;
  3. import 'package:printing/printing.dart';
复制代码
然后补充
  1. _capturePng
复制代码
方法:
  1. Future<void> _capturePng(BuildContext ctx) async {
  2.   try {
  3.     // 添加 print
  4.     final doc = pw.Document();

  5.     RenderRepaintBoundary? boundary = boundaryKey.currentContext
  6.       ?.findRenderObject() as RenderRepaintBoundary?;
  7.     ui.Image? image = await boundary?.toImage(pixelRatio: 3.0);
  8.     ByteData? byteData =
  9.       await image?.toByteData(format: ui.ImageByteFormat.png);

  10.     final pageFormat = PdfPageFormat.a4;
  11.   
  12.     print(MediaQuery.of(ctx).size.height); // 测试打印界面的高度

  13.     doc.addPage(pw.Page(
  14.       pageFormat: pageFormat,
  15.       orientation: pw.PageOrientation.landscape,
  16.       build: (pw.Context context) {
  17.         return pw.Center(
  18.           child: pw.Image( // 图像挂件
  19.             pw.MemoryImage(_imageBytes),
  20.             width: pageFormat.height - 20,
  21.             fit: pw.BoxFit.fitWidth,
  22.           ),
  23.         );
  24.       }));

  25.     // 打印
  26.     await Printing.layoutPdf(
  27.       onLayout: (PdfPageFormat format) async => doc.save(),
  28.     );
  29.   } catch (e) {
  30.     print(e);
  31.   }
  32. }
复制代码
上面,我们通过
  1. pw.MemoryImage(_imageBytes)
复制代码
指定
  1. Image
复制代码
的内容,并调起打印机打印~
为了方便演示,看到边界,我们更改了下 UI
4.webp

当然,我们可以设定其打印的边距和指定内容的方向等:
  1. pw.Page(
  2.   orientation: pw.PageOrientation.landscape, // 内容的方向
  3.   margin: pw.EdgeInsets.all(16.0), // 边距
  4.   ...
  5. )
复制代码
以上就是Flutter实现打印功能的示例详解的详细内容,更多关于Flutter打印的资料请关注晓枫资讯其它相关文章!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
晓枫资讯-科技资讯社区-免责声明
免责声明:以上内容为本网站转自其它媒体,相关信息仅为传递更多信息之目的,不代表本网观点,亦不代表本网站赞同其观点或证实其内容的真实性。
      1、注册用户在本社区发表、转载的任何作品仅代表其个人观点,不代表本社区认同其观点。
      2、管理员及版主有权在不事先通知或不经作者准许的情况下删除其在本社区所发表的文章。
      3、本社区的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,举报反馈:点击这里给我发消息进行删除处理。
      4、本社区一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
      5、以上声明内容的最终解释权归《晓枫资讯-科技资讯社区》所有。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
15
积分
10
注册时间
2022-12-26
最后登录
2022-12-26

发表于 2024-9-11 16:52:03 | 显示全部楼层
路过,支持一下
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
17
积分
14
注册时间
2022-12-25
最后登录
2022-12-25

发表于 2024-10-16 00:25:59 | 显示全部楼层
感谢楼主,顶。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
16
积分
12
注册时间
2022-12-25
最后登录
2022-12-25

发表于 2024-12-8 03:02:11 | 显示全部楼层
感谢楼主分享。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
17
积分
14
注册时间
2022-12-27
最后登录
2022-12-27

发表于 2025-4-14 04:30:00 | 显示全部楼层
顶顶更健康!!!
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~
严禁发布广告,淫秽、色情、赌博、暴力、凶杀、恐怖、间谍及其他违反国家法律法规的内容。!晓枫资讯-社区
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

1楼
2楼
3楼
4楼
5楼

手机版|晓枫资讯--科技资讯社区 本站已运行

CopyRight © 2022-2025 晓枫资讯--科技资讯社区 ( BBS.yzwlo.com ) . All Rights Reserved .

晓枫资讯--科技资讯社区

本站内容由用户自主分享和转载自互联网,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。

如有侵权、违反国家法律政策行为,请联系我们,我们会第一时间及时清除和处理! 举报反馈邮箱:点击这里给我发消息

Powered by Discuz! X3.5

快速回复 返回顶部 返回列表