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)建項目。
我們?nèi)绾未蛴?/h2>
關(guān)于調(diào)起 printer 打印的功能。我們有以下的想法:
- 打印當(dāng)前路由頁面的內(nèi)容,類似于網(wǎng)頁的調(diào)用
window.print方式打印 - 打印頁面中指定的
widget的內(nèi)容 - 打印重組的
widget的內(nèi)容 - 將頁面指定的
widget轉(zhuǎn)化為image之后,再調(diào)起打印
針對第一點,我們并沒有發(fā)現(xiàn)在 app 中有類似 window.print 的方法;而對第二點,我們也不能指定頁面中 widget 進行打印。剩下的第三點和第四點,我們都可以實現(xiàn)。
接下來,我們將應(yīng)用 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 是可選,筆者在調(diào)試 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 相關(guān)包。
因為我們是在 macos 上進行調(diào)試,我們還需要在 macos/Runner/Release.entitlements 和 macos/Runner/DebugProfile.entitlements 文件中添加內(nèi)容:
<key>com.apple.security.print</key> <true/>
如果是其他平臺開發(fā)調(diào)試,請參考 printing 引入相關(guān)的內(nèi)容。
之后我們在 main.dart 中實現(xiàn)相關(guān)的邏輯:
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Print Demo'),
),
body: Center(
child: ElevatedButton(
onPressed: _printPdf,
child: Text('Print'),
),
),
);
}
上面我們編寫了相關(guān)的 widget,展示一個 Print 按鈕,當(dāng)點擊按鈕時候,觸發(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,然后調(diào)起打印機 Printing.layoutPdf,動態(tài)如下

那么,對于復(fù)雜的內(nèi)容,如果我們還是編寫自定義的 widgets 的話,那不切實際,維護成本高。那么,我們有什么方法打印它呢?這就是下面我們要介紹的了~
widgets 內(nèi)容轉(zhuǎn) image,再打印 image
我們直接將頁面上的 widgets 內(nèi)容轉(zhuǎn)換為 image,再結(jié)合上面提及的打印組合的 widgets 處理即可。
將 widgets 內(nèi)容轉(zhuǎn) 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 的文本值。當(dāng)我們點擊 ElevatedButton 掛件時候,會觸發(fā) _capturePng 方法。在 _capturePng 方法中,我們將區(qū)域內(nèi)的內(nèi)容轉(zhuǎn)換為圖像,并且,將圖像轉(zhuǎn)為位數(shù)據(jù),給 _imageBytes 賦值,展現(xiàn)在頁面上。相關(guān) Gif 圖如下

整合 Image 掛件
在上面的例子中,我們保存了生成的圖數(shù)據(jù)。接下來,我們將該圖片打印出來。上面的代碼,我們在原始基礎(chǔ)上更改:
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 的內(nèi)容,并調(diào)起打印機打印~
為了方便演示,看到邊界,我們更改了下 UI

當(dāng)然,我們可以設(shè)定其打印的邊距和指定內(nèi)容的方向等:
pw.Page( orientation: pw.PageOrientation.landscape, // 內(nèi)容的方向 margin: pw.EdgeInsets.all(16.0), // 邊距 ... )
以上就是Flutter實現(xiàn)打印功能的示例詳解的詳細內(nèi)容,更多關(guān)于Flutter打印的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
android中UIColletionView瀑布流布局實現(xiàn)思路以及封裝的實現(xiàn)
本篇文章主要介紹了android中UIColletionView瀑布流布局實現(xiàn)思路以及封裝的實現(xiàn),具有一定的參考價值,有興趣的可以了解一下。<BR>2017-02-02
Kotlin對象的懶加載方式by?lazy?與?lateinit?異同詳解
這篇文章主要為大家介紹了Kotlin對象的懶加載方式by?lazy?與?lateinit?異同詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-10-10
Android中自定義view實現(xiàn)側(cè)滑效果
這篇文章主要介紹了Android中自定義view實現(xiàn)側(cè)滑效果的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2016-11-11
Android開發(fā)之手勢檢測及通過手勢實現(xiàn)翻頁功能的方法
這篇文章主要介紹了Android開發(fā)之手勢檢測及通過手勢實現(xiàn)翻頁功能的方法,結(jié)合實例形式分析了Android GestureDetector類實現(xiàn)手勢檢測功能的相關(guān)操作技巧,需要的朋友可以參考下2017-09-09
android實現(xiàn)okHttp的get和post請求的簡單封裝與使用
這篇文章主要介紹了android實現(xiàn)okHttp的get和post請求的簡單封裝與使用,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-05-05
Cocos2d-x 3.0中集成社交分享ShareSDK的詳細步驟和常見問題解決
這篇文章主要介紹了Cocos2d-x 3.0中集成社交分享ShareSDK的詳細步驟和常見問題的解決方法以及需要注意的問題,需要的朋友可以參考下2014-04-04
Android使用OKHttp包處理HTTP相關(guān)操作的基本用法講解
這篇文章主要介紹了Android使用OKHttp包處理HTTP相關(guān)操作的基本用法講解,包括操作如何利用OKHttp操作HTTP請求與處理緩存等內(nèi)容,需要的朋友可以參考下2016-07-07

