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