【问题标题】:An inner widget tree cannot be bigger than a page: A Widget cannot be drawn partially on one page and the remaining on another page: It's insecable内部小部件树不能大于页面:一个小部件不能在一个页面上部分绘制,而其余部分在另一页面上:它是不可分割的
【发布时间】:2022-01-22 19:45:15
【问题描述】:

在这个 Multipage 类 https://pub.dev/documentation/pdf/latest/widgets/MultiPage-class.html 中明确提到内部小部件树不能大于页面:小部件不能部分绘制在一个页面上,而其余部分则绘制在另一个页面上: 这是不安全的。

我想使用这个pdf 插件生成视图。

import 'package:pdf/pdf.dart';
import 'package:pdf/widgets.dart' as pw;
import '../utils/page_data.dart';

makeTemplate3(pw.Document doc, pw.PageTheme pageTheme, PageData pageData,
    pw.MemoryImage profileImagee) {
  List<LineItems> _product = [];
  for (var i = 0; i < 100; i++) {
    int pos = i + 1;
    _product.add(
      LineItems(
        id: '$pos',
        name: 'Product',
        price: '100$i',
        quantity: '200$i',
        total: 'Total Sum: ' + (i * 200).toString(),
        desc:
            'Test widget $i: An inner widget tree cannot be bigger than a page: A Widget cannot be drawn partially on one page and the remaining on another page: Its insecable. A small set of Widget can automatically span over multiple pages, and can be used as a direct child of the build method: Flex, Partition, Table, Wrap, GridView, and Column.',
      ),
    );
  }

  doc.addPage(
    pw.MultiPage(
        pageTheme: pageTheme,
        build: (pw.Context context) => <pw.Widget>[
              _headerLayout(),
              // ignore: sdk_version_ui_as_code
              for (int i = 0; i < _product.length; i++)
                _productLayout(_product[i]),
            ]),
  );

  return doc;
}

_headerLayout() {
  return new pw.Container(
      padding: pw.EdgeInsets.all(20.0),
      height: 80.0,
      color: PdfColors.blue,
      child: pw.Row(
        crossAxisAlignment: pw.CrossAxisAlignment.start,
        children: [
          pw.Container(
            child: pw.Text(
              'Header',
              style: pw.TextStyle(fontWeight: pw.FontWeight.bold, fontSize: 25),
            ),
          ),
        ],
      ));
}

_productLayout(LineItems item) {
  return new pw.Container(
      margin: pw.EdgeInsets.all(20.0),
      child: pw.Column(
        crossAxisAlignment: pw.CrossAxisAlignment.start,
        children: <pw.Widget>[
          pw.Column(crossAxisAlignment: pw.CrossAxisAlignment.start, children: [
            pw.Container(
              padding: pw.EdgeInsets.only(bottom: 20),
              child: pw.Text(
                item.name.toString() + ' - ID: ' + item.id.toString(),
                style:
                    pw.TextStyle(fontWeight: pw.FontWeight.bold, fontSize: 20),
              ),
            ),
            pw.Container(
              padding: pw.EdgeInsets.only(bottom: 10),
              child: pw.Text(
                  'Qty: ' +
                      item.quantity.toString() +
                      ' x Cost: £' +
                      item.price,
                  style: pw.TextStyle(
                      fontWeight: pw.FontWeight.normal, fontSize: 16)),
            ),
            pw.Container(
                padding: pw.EdgeInsets.only(bottom: 10),
                child: pw.Text(
                  '£' + item.total.toString(),
                  style: pw.TextStyle(
                      fontWeight: pw.FontWeight.normal, fontSize: 14),
                )),
            pw.Text('Description: ' + item.desc,
                style: pw.TextStyle(
                    fontWeight: pw.FontWeight.normal, fontSize: 16)),
            getSubItemList()
          ]),
        ],
      ));
}

pw.Widget getSubItemList() {
  List<pw.Container> list = [];
  for (int i = 0; i < 25; i++) {
    list.add(
      pw.Container(
          child: pw.Text(
              'Sub Product: $i                         Total Sum:   $i-475',
              style: pw.TextStyle(
                  fontWeight: pw.FontWeight.normal, fontSize: 16))),
    );
  }

  return pw.Container(
      padding: pw.EdgeInsets.all(20), child: pw.Column(children: list));
}

class LineItems {
  String total, price, quantity, name, id, desc;
  LineItems(
      {this.total, this.price, this.quantity, this.name, this.id, this.desc});
}

【问题讨论】:

    标签: flutter pdf printing pdf-generation dart-pdf


    【解决方案1】:

    这不是一个复杂的布局。您需要做的就是将每个块扁平化为 MultiPage 子级。

    试试这个:

    import 'dart:typed_data';
    
    import 'package:flutter/material.dart';
    import 'package:pdf/pdf.dart';
    import 'package:pdf/widgets.dart' as pw;
    import 'package:printing/printing.dart';
    
    Future<void> main() async {
      runApp(const MyApp('Printing Demo'));
    }
    
    class MyApp extends StatelessWidget {
      const MyApp(this.title, {Key? key}) : super(key: key);
    
      final String title;
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: Scaffold(
            appBar: AppBar(title: Text(title)),
            body: PdfPreview(
              build: (format) => _generatePdf(format, title),
            ),
          ),
        );
      }
    
      Future<Uint8List> _generatePdf(PdfPageFormat format, String title) async {
        final pdf = pw.Document();
    
        List<LineItems> _product = [];
        for (var i = 0; i < 100; i++) {
          int pos = i + 1;
          _product.add(
            LineItems(
              id: '$pos',
              name: 'Product',
              price: '100$i',
              quantity: '200$i',
              total: 'Total Sum: ' + (i * 200).toString(),
              desc:
                  'Test widget $i: An inner widget tree cannot be bigger than a page: A Widget cannot be drawn partially on one page and the remaining on another page: Its insecable. A small set of Widget can automatically span over multiple pages, and can be used as a direct child of the build method: Flex, Partition, Table, Wrap, GridView, and Column.',
            ),
          );
        }
    
        pdf.addPage(
          pw.MultiPage(
            pageFormat: format,
            header: _headerLayout,
            footer: (pw.Context context) {
              return pw.Container(
                  alignment: pw.Alignment.centerRight,
                  margin: const pw.EdgeInsets.only(top: 1.0 * PdfPageFormat.cm),
                  child: pw.Text(
                      'Page ${context.pageNumber} of ${context.pagesCount}',
                      style: pw.Theme.of(context)
                          .defaultTextStyle
                          .copyWith(color: PdfColors.grey)));
            },
            build: (pw.Context context) => <pw.Widget>[
              for (int i = 0; i < _product.length; i++)
                ..._productLayout(_product[i]),
            ],
          ),
        );
    
        return pdf.save();
      }
    }
    
    pw.Widget _headerLayout(pw.Context context) {
      return pw.Container(
        padding: const pw.EdgeInsets.all(20.0),
        height: 80.0,
        color: PdfColors.blue,
        child: pw.Row(
          crossAxisAlignment: pw.CrossAxisAlignment.start,
          children: [
            pw.Container(
              child: pw.Text(
                'Header',
                style: pw.TextStyle(fontWeight: pw.FontWeight.bold, fontSize: 25),
              ),
            ),
          ],
        ),
      );
    }
    
    Iterable<pw.Widget> _productLayout(LineItems item) sync* {
      yield pw.Container(
        padding: const pw.EdgeInsets.all(20),
        child: pw.Text(
          item.name.toString() + ' - ID: ' + item.id.toString(),
          style: pw.TextStyle(fontWeight: pw.FontWeight.bold, fontSize: 20),
        ),
      );
      yield pw.Container(
        padding: const pw.EdgeInsets.only(bottom: 10, left: 20, right: 20),
        child: pw.Text(
          'Qty: ' + item.quantity.toString() + ' x Cost: £' + item.price,
          style: pw.TextStyle(
            fontWeight: pw.FontWeight.normal,
            fontSize: 16,
          ),
        ),
      );
      yield pw.Container(
        padding: const pw.EdgeInsets.only(bottom: 10, left: 20, right: 20),
        child: pw.Text(
          '£' + item.total.toString(),
          style: pw.TextStyle(fontWeight: pw.FontWeight.normal, fontSize: 14),
        ),
      );
      yield pw.Container(
        padding: const pw.EdgeInsets.only(left: 20, right: 20),
        child: pw.Text(
          'Description: ' + item.desc,
          style: pw.TextStyle(
            fontWeight: pw.FontWeight.normal,
            fontSize: 16,
          ),
        ),
      );
      yield pw.SizedBox(height: 20);
      yield* getSubItemList();
      yield pw.SizedBox(height: 20);
    }
    
    Iterable<pw.Widget> getSubItemList() sync* {
      for (int i = 0; i < 25; i++) {
        yield pw.Container(
          padding: const pw.EdgeInsets.only(left: 30, right: 20),
          child: pw.Text(
            'Sub Product: $i                         Total Sum:   $i-475',
            style: pw.TextStyle(
              fontWeight: pw.FontWeight.normal,
              fontSize: 16,
            ),
          ),
        );
      }
    }
    
    class LineItems {
      String total, price, quantity, name, id, desc;
      LineItems({
        required this.total,
        required this.price,
        required this.quantity,
        required this.name,
        required this.id,
        required this.desc,
      });
    }
    

    【讨论】:

    • 它在这个简单的案例中工作。但是当孩子有动态内容到它的标题时。我们如何解决这个问题?
    • 什么样的内容?
    • 动态内容,它使用新的容器小部件及其自己的子列表。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-26
    • 1970-01-01
    • 2020-07-28
    • 2012-01-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多