ウーオでアプリ(UUUO, UUUO Sellers)の開発を担当している榎本です。
ウーオでは、お魚を出品したい方向けの「UUUO Sellers」というアプリを提供しています。 以前、こちらの記事で、Web版のUUUO SellersをFlutter Webで作った話をしました。 今回の記事は、消費地市場に届いた荷物の配送情報の連携に用いる配送指示書と呼ばれる書類をPDFとして出力する機能をWeb版のUUUO Sellersに追加した話です。
環境
実装
pdfライブラリ、printingライブラリの導入
FlutterでPDFを生成したい場合は、pdfライブラリが便利です。 また、印刷したい場合は、printingライブラリを使いましょう。 まずはpubspec.yamlに以下を追加しましょう。
dependencies: pdf: ^3.10.4 printing: ^5.11.0
PDFファイルの生成方法
最低限のコードでPDFファイルを生成できるか試しましょう。
以下のコードをmain.dartに貼り付けて、flutter run -d chrome
でアプリを起動しましょう。
右下のFABを押すと、印刷プレビュー画面が開くと思います。現時点では空のContainerしか中身が無いので真っ白のPDFファイルが表示されます。
import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:pdf/pdf.dart'; import 'package:pdf/widgets.dart' as pw; import 'package:printing/printing.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar( title: Text('PDFデモ'), ), floatingActionButton: FloatingActionButton( child: Icon(Icons.print), tooltip: '印刷', onPressed: () { // 印刷プレビューを表示する Printing.layoutPdf( onLayout: (_) { // PDFファイルを生成する return buildPdf(); }, ); }, ), body: Center( child: Text('右下のボタンを押してPDFファイルを生成'), ), ), ); } // PDFファイルを生成 Future<Uint8List> buildPdf() async { final pw.Document doc = pw.Document(); doc.addPage( pw.MultiPage( pageFormat: PdfPageFormat.a4.copyWith( marginTop: 10, marginBottom: 10, marginLeft: 20, marginRight: 20, ), build: (pw.Context context) { return [ // ここにPDFの中身を作る pw.Container(), ]; }, ), ); return await doc.save(); } }
Widgetの作り方
pdfファイルの中身の実装では、Flutterの標準Widgetを使うことはできません。
代わりにpackage:pdf/widgets.dart
のWidgetを使用します。
ただし、Widget名はFlutterの標準Widgetと同じため、名前の衝突が起きるので、as pw
と付けてimportしましょう。
import 'package:pdf/widgets.dart' as pw;
通常のFlutterのWidget(Containerなど)の先頭に、pwを付けて呼ぶとPDF用のWidgetを使用できます
pw.Column( children: [ pw.Container( child: pw.Text('test') ), ] )
PDFのサイズ指定と余白の指定
PDFファイルのサイズを変更するには、pw.MultiPage()のpageFormatにPdfPageFormat.a4
にように指定するとA4サイズのPDFになります。
また、marginTop, marginBottom, marginLeft, marginRightで余白の調整が可能です。
PdfPageFormat.a4.copyWith( marginTop: 10, marginBottom: 10, marginLeft: 20, marginRight: 20, );
表(Table)の作り方
pw.TableHelper.fromTextArray()
を使用するとFlutterの標準WidgetのTableと同じような感覚でTableを作成できます。
以下のWidgetをmain.dart
内に定義して、pw.MultiPage()から呼んでみましょう。
アプリを実行して、印刷ボタンを押すとテーブルが表示されていると思います。
また、1つのセルの高さが高すぎる場合に、セル内で改ページしてしまうのではないかと心配になるかと思います。安心してください、いい感じに改ページしてくれます。
テーブルの細かい設定はたくさんあるためここでは割愛します。
pw.Widget _table() { // ヘッダー行 final tableHeaders = [ pw.Text('name'), pw.Text('height'), pw.Text('weight'), ]; // データ final data = [ [ pw.Text('Eren'), pw.Text('170cm'), pw.Text('63kg'), ], [ pw.Text('Armin'), pw.Text('163cm'), pw.Text('55kg'), ], [ pw.Text('Levi'), pw.Text('160cm'), pw.Text('65kg'), ], ]; return pw.TableHelper.fromTextArray( headers: List<pw.Widget>.generate( tableHeaders.length, (col) => tableHeaders[col], ), data: List<List<pw.Widget>>.generate( data.length, (row) => List<pw.Widget>.generate( tableHeaders.length, (col) => data[row][col], ), ), ); }
フォントの指定の仕方
フォントを指定することもできます。以下のようにttfファイルを読み込んで使用する必要があります。(otfファイルには対応していません)
final regularFont = rootBundle.load( 'assets/fonts/NotoSansJPTTF/NotoSansJP-Regular.ttf', ); pw.Text('test', style: pw.TextStyle(font: regularFont))
最大ページ数に制限がある
PDFファイルのページ数が多くなると、エラーになることがありますが、実はpw.MultiPage()
は初期状態では20ページまでしか生成できません。
20ページ以上を生成した場合は、maxPages
に数値を指定しましょう。最大ページ数に制限を設けている理由はわかりませんが、おそらくパフォーマンス的な事だろうと思います。
pw.MultiPage( maxPages: 50 )
まとめ
- pdfライブラリを使用するとFlutterで画面を作るようにPDFを生成できる
最後に
ウーオでは水産流通を革新するため、プロダクトを通じてあらゆるアプローチをしています。ウーオの事業やプロダクト開発にご興味がある方は、以下をぜひご覧ください 👇