Flutter分页文本展示插件paginated_text的使用

发布于 1周前 作者 itying888 来自 Flutter

Flutter分页文本展示插件paginated_text的使用

简介

paginated_text 是一个Flutter插件,提供了分页文本视图,并且可以选择自动调整大小的首字下沉效果。该插件允许你根据需要自定义动画和控件,同时提供了一个控制器和一个带有构建器的Widget,但你也可以创建自己的自定义Widget。

paginated_text_demo.gif

功能特性

  • 自动分页:文本会根据Widget的布局大小自动分页。
  • 自定义动画和控件:你可以使用任何你喜欢的动画和控件,或者完全不使用动画。
  • 首字下沉
    • 首字可以是自动定位和调整大小的下沉字母。
    • 计算并缓存了下沉字母和正文字体的实际字母高度(使用字母’Z’)。
    • 下沉字母的基线可以对齐到第n行文本的基线(通过capLines配置)。
    • 下沉字母的顶部与第一行文本的顶部对齐。
    • 注意:此方法目前对哥特式、手写体或书法字体效果不佳。
  • 解析内联Markdown:支持解析内联Markdown(从drop_cap_text包中继承)。
  • 自动分页:可以根据不同的规则自动分页。
enum PageBreak {
  /// 在页面的最后一可见单词处断页
  word,

  /// 尝试在句号、逗号、分号或破折号处断页
  sentenceFragment,

  /// 尝试在句子结束处断页
  sentence,

  /// 尝试在段落(两个连续的换行符)处断页
  paragraph;
}

使用方法

paginated_text 插件没有其他依赖,只需要Dart 3 / Flutter 3 和 collection 包。以下是基本的使用示例:

import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:paginated_text/paginated_text.dart';

void main() {
  runApp(const MainApp());
}

class MainApp extends StatelessWidget {
  const MainApp({super.key});

  [@override](/user/override)
  Widget build(BuildContext context) {
    final text = pwp.trim(); // 示例文本
    final style = GoogleFonts.notoSerif(fontSize: 36, height: 1.5); // 正文样式
    final dropCapStyle = GoogleFonts.calligraffitti(); // 下沉字母样式

    return MaterialApp(
      themeMode: ThemeMode.dark,
      theme: ThemeData.dark(),
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        body: PaginatedExample(
          text: text,
          style: style,
          dropCapStyle: dropCapStyle,
        ),
      ),
    );
  }
}

class PaginatedExample extends StatefulWidget {
  const PaginatedExample({
    super.key,
    required this.text,
    required this.style,
    required this.dropCapStyle,
  });

  final String text;
  final TextStyle style;
  final TextStyle dropCapStyle;

  [@override](/user/override)
  State<PaginatedExample> createState() => _PaginatedExampleState();
}

class _PaginatedExampleState extends State<PaginatedExample>
    with SingleTickerProviderStateMixin {
  late Future _googleFontsPending;
  late PaginatedController _controller;

  [@override](/user/override)
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  [@override](/user/override)
  void initState() {
    super.initState();
    _controller = PaginatedController(PaginateData(
      text: widget.text,
      dropCapLines: 3, // 下沉字母占据的行数
      style: widget.style,
      dropCapStyle: widget.dropCapStyle,
      pageBreakType: PageBreakType.paragraph, // 分页类型
      breakLines: 1, // 分页时保留的空白行数
      resizeTolerance: 3, // 字体调整容差
      parseInlineMarkdown: true, // 解析内联Markdown
    ));

    _googleFontsPending = GoogleFonts.pendingFonts([
      widget.style,
      widget.dropCapStyle,
    ]);
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return FutureBuilder(
        future: _googleFontsPending,
        builder: (context, snapshot) {
          if (snapshot.connectionState != ConnectionState.done) {
            return const CircularProgressIndicator.adaptive();
          }

          final reverse = _controller.pageIndex < _controller.previousPageIndex;

          return Padding(
            padding: const EdgeInsets.all(16),
            child: PaginatedText(
              _controller,
              builder: (context, child) {
                return DefaultTextStyle(
                  style: widget.style,
                  child: Column(
                    children: [
                      Text('The Promise of World Peace',
                          style: widget.dropCapStyle.copyWith(
                              fontSize: 40, fontStyle: FontStyle.italic)),
                      Expanded(
                        child: PageTransitionSwitcher(
                          duration: const Duration(seconds: 1),
                          reverse: reverse,
                          transitionBuilder:
                              (child, primaryAnimation, secondaryAnimation) {
                            const offscreen = Offset(-1.5, 0.0);
                            return SlideTransition(
                              position: Tween<Offset>(
                                begin: Offset.zero,
                                end: offscreen,
                              ).animate(secondaryAnimation),
                              child: FadeTransition(
                                opacity: Tween<double>(
                                  begin: 0.0,
                                  end: 1.0,
                                ).animate(primaryAnimation),
                                child: child,
                              ),
                            );
                          },
                          child: Padding(
                            key: ValueKey(_controller.currentPage.pageIndex),
                            padding: const EdgeInsets.all(40),
                            child: SelectionArea(child: child),
                          ),
                        ),
                      ),
                      const SizedBox(height: 20),
                      Text(
                          'Page ${_controller.pageNumber} of ${_controller.numPages}',
                          style: widget.style.copyWith(fontSize: 24)),
                      const SizedBox(height: 20),
                      ButtonBar(
                        alignment: MainAxisAlignment.center,
                        children: [
                          TextButton(
                            onPressed: _controller.isFirst
                                ? null
                                : () {
                                    setState(() {
                                      _controller.previous();
                                    });
                                  },
                            child: const Padding(
                              padding: EdgeInsets.all(8.0),
                              child:
                                  Text('Prev', style: TextStyle(fontSize: 30)),
                            ),
                          ),
                          TextButton(
                            onPressed: _controller.isLast
                                ? null
                                : () {
                                    setState(() {
                                      _controller.next();
                                    });
                                  },
                            child: const Padding(
                              padding: EdgeInsets.all(8.0),
                              child:
                                  Text('Next', style: TextStyle(fontSize: 30)),
                            ),
                          ),
                        ],
                      ),
                    ],
                  ),
                );
              },
            ),
          );
        });
  }
}

更多关于Flutter分页文本展示插件paginated_text的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter分页文本展示插件paginated_text的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何在Flutter中使用paginated_text插件来实现分页文本展示的示例代码。这个插件允许你在一个页面上显示长文本,并允许用户通过滑动来浏览不同的页面。

首先,你需要在你的pubspec.yaml文件中添加paginated_text依赖:

dependencies:
  flutter:
    sdk: flutter
  paginated_text: ^x.y.z  # 请替换为最新的版本号

然后,运行flutter pub get来安装依赖。

接下来,你可以在你的Dart文件中使用PaginatedText小部件。下面是一个完整的示例代码:

import 'package:flutter/material.dart';
import 'package:paginated_text/paginated_text.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Paginated Text Example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        appBar: AppBar(
          title: Text('Paginated Text Example'),
        ),
        body: Center(
          child: PaginatedTextExample(),
        ),
      ),
    );
  }
}

class PaginatedTextExample extends StatefulWidget {
  @override
  _PaginatedTextExampleState createState() => _PaginatedTextExampleState();
}

class _PaginatedTextExampleState extends State<PaginatedTextExample> {
  final String longText = """
  这是一个很长的文本示例,用于展示paginated_text插件的分页功能。
  你可以在这里添加任意长度的文本内容,paginated_text会自动将其分页显示。
  每一页的内容会根据屏幕大小自动调整,以提供最佳的阅读体验。
  
  继续添加一些内容,以确保文本足够长,能够展示分页效果。
  分页功能在处理长文档或电子书时特别有用,用户可以轻松地在页面上滑动浏览。
  
  希望这个示例能够帮助你理解如何使用paginated_text插件。
  如果你有任何问题或建议,请随时与我们联系。
  """;

  @override
  Widget build(BuildContext context) {
    return PaginatedText(
      text: longText,
      style: TextStyle(fontSize: 18),
      builder: (context, state) {
        return Padding(
          padding: EdgeInsets.all(16.0),
          child: state.widget,
        );
      },
    );
  }
}

在这个示例中,我们创建了一个简单的Flutter应用,其中包含一个PaginatedText小部件。PaginatedText小部件接受以下参数:

  • text:要显示的文本内容。
  • style:文本的样式。
  • builder:一个可选的builder函数,允许你对分页文本的布局进行自定义。在这个例子中,我们使用了Padding来添加一些内边距。

运行这个应用,你会看到一个长文本被分页显示,并且你可以通过滑动来浏览不同的页面。

请注意,这个示例代码仅展示了paginated_text插件的基本用法。根据实际需求,你可以进一步自定义和扩展这个插件的功能。

回到顶部