Flutter實現(xiàn)打印功能的示例詳解
開發(fā)環(huán)境
Flutter Version:3.16.4- 系統(tǒng):
macOS Sonoma-Apple M1芯片 Android Studio: 17.0.7

我們通過 flutter create project_name 創(chuàng)建項目。
我們如何打印
關于調起 printer 打印的功能。我們有以下的想法:
- 打印當前路由頁面的內容,類似于網(wǎng)頁的調用
window.print方式打印 - 打印頁面中指定的
widget的內容 - 打印重組的
widget的內容 - 將頁面指定的
widget轉化為image之后,再調起打印
針對第一點,我們并沒有發(fā)現(xiàn)在 app 中有類似 window.print 的方法;而對第二點,我們也不能指定頁面中 widget 進行打印。剩下的第三點和第四點,我們都可以實現(xiàn)。
接下來,我們將應用 flutter printing 包,來演示后兩種實現(xiàn)方式。
引入 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,請以 官網(wǎng) 版本為主
然后,我們可以通過 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/>
如果是其他平臺開發(fā)調試,請參考 printing 引入相關的內容。
之后我們在 main.dart 中實現(xiàn)相關的邏輯:
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Print Demo'),
),
body: Center(
child: ElevatedButton(
onPressed: _printPdf,
child: Text('Print'),
),
),
);
}
上面我們編寫了相關的 widget,展示一個 Print 按鈕,當點擊按鈕時候,觸發(fā)方法 _printPdf,該方法的實現(xiàn)如下
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,動態(tài)如下

那么,對于復雜的內容,如果我們還是編寫自定義的 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 來指定了重繪的區(qū)域為 200*200 的文本值。當我們點擊 ElevatedButton 掛件時候,會觸發(fā) _capturePng 方法。在 _capturePng 方法中,我們將區(qū)域內的內容轉換為圖像,并且,將圖像轉為位數(shù)據(jù),給 _imageBytes 賦值,展現(xiàn)在頁面上。相關 Gif 圖如下

整合 Image 掛件
在上面的例子中,我們保存了生成的圖數(shù)據(jù)。接下來,我們將該圖片打印出來。上面的代碼,我們在原始基礎上更改:
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), // 邊距 ... )
以上就是Flutter實現(xiàn)打印功能的示例詳解的詳細內容,更多關于Flutter打印的資料請關注腳本之家其它相關文章!
相關文章
Android自定義listview布局實現(xiàn)上拉加載下拉刷新功能
這篇文章主要介紹了Android自定義listview布局實現(xiàn)上拉加載下拉刷新功能,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2016-12-12
Android自定義View實現(xiàn)葉子飄動旋轉效果(四)
這篇文章主要為大家詳細介紹了Android自定義View實現(xiàn)葉子飄動旋轉效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-03-03
Android 中ScrollView與ListView沖突問題的解決辦法
這篇文章主要介紹了Android 中ScrollView與ListView沖突問題的解決辦法的相關資料,希望通過本文能幫助到大家,讓大家掌握解決問題的辦法,需要的朋友可以參考下2017-10-10
android使用Messenger綁定Service的多種實現(xiàn)方法
android使用Messenger綁定Service的多種實現(xiàn)方法,需要的朋友可以參考一下2013-05-05

