Flutter页面指示器插件faabul_page_indicator的使用

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

Flutter页面指示器插件faabul_page_indicator的使用

faabul_page_indicator 是由 Faabul Live Quizzes 开发和使用的插件。

另一个点指示器?

我们创建了这个包,因为它能满足以下需求:

  • 支持自定义“点”构建器
  • 在页数过多且指示器空间受限的情况下,具有良好的用户体验
  • 同时支持LTR(从左到右)和RTL(从右到左)语言环境
  • 具有良好的性能

使用方法

请参阅 示例 获取完整的示例代码。

只需将指示器传递给现有的控制器和页面数量,即可显示默认的点指示器:

late final _controller = PageController();

[@override](/user/override)
Widget build(BuildContext context) {
    return Column(
        children: [
            Expanded(
                child: PageView.builder(
                    itemCount: 20,
                    itemBuilder: _buildPage,
                    controller: _controller,
                ),
            ),
            FaabulPageIndicator(
                itemCount: 20,
                controller: _controller,
            ),
        ],
    );
}

指示器会自动处理溢出情况,并在页面之间进行点击导航。

如果你需要不同的样式或功能,可以传递一个自定义构建器。你可以使用默认的 FaabulPageIndicatorDot 或任何你喜欢的小部件。

FaabulPageIndicator(
    itemCount: 20,
    itemSize: Size(30, 30),
    controller: _controller,
    itemBuilder: (BuildContext context, int index, int? currentPage) => 
        FaabulPageIndicatorDot(
            key: ValueKey(index),
            size: 30,
            decoration: index == currentPage
                ? BoxDecoration(
                    border: Border.all(
                        color: colorScheme.primary, width: 2),
                    borderRadius: BorderRadius.circular(8),
                    color: colorScheme.primaryContainer,
                )
                : BoxDecoration(
                    border: Border.all(
                        color: colorScheme.outlineVariant,
                        width: 2),
                    borderRadius: BorderRadius.circular(4),
                ),
            isActive: index == currentPage,
            onTap: () => _controller.jumpToPage(index),
        ),
)

你也可以传递任何小部件,使每个“点”独一无二:

使用自定义构建器时,请确保渲染的点大小与 itemSize 属性相对应。

性能

FaabulPageIndicator 针对性能进行了优化。它内部使用了 ListView.builder 来显示点。这意味着只有可见的点才会被渲染,并且该指示器可以处理大量页面而不会出现性能下降。内部指示器仅在实际页面(作为整数)在 PageController 中发生变化时才进行工作。

实时查看

你可以在 Faabul Live Quizzes 应用中实时查看指示器的效果。每次玩测验时都可以看到。

完整示例代码

以下是完整的示例代码,展示了如何使用 faabul_page_indicator 插件:

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

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

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

  [@override](/user/override)
  Widget build(BuildContext context) {
    late final headlineStyle = Theme.of(context).textTheme.headlineMedium;
    late final colorScheme = Theme.of(context).colorScheme;
    return MaterialApp(
      title: 'Flutter Demo',
      home: Scaffold(
        body: SafeArea(
          bottom: false,
          child: Center(
            child: ConstrainedBox(
              constraints: const BoxConstraints(maxWidth: 600),
              child: SingleChildScrollView(
                padding: const EdgeInsets.all(32),
                child: Column(
                  children: [
                    Text('3 pages', style: headlineStyle),
                    const _PageView(pages: 3),
                    const Divider(height: 64),
                    Text('42 pages', style: headlineStyle),
                    const _PageView(pages: 42, initialPage: 21),
                    const Divider(height: 64),
                    Text('Customized FaabulPageIndicatorDot', style: headlineStyle),
                    _PageView(
                        pages: 16,
                        initialPage: 0,
                        size: 30,
                        itemBuilder: (
                          BuildContext context,
                          int index,
                          int? currentPage,
                        ) => FaabulPageIndicatorDot(
                              key: ValueKey(index),
                              size: 30,
                              decoration: index == currentPage
                                  ? BoxDecoration(
                                      border: Border.all(
                                          color: colorScheme.primary, width: 2),
                                      borderRadius: BorderRadius.circular(8),
                                      color: colorScheme.primaryContainer,
                                    )
                                  : BoxDecoration(
                                      border: Border.all(
                                          color: colorScheme.outlineVariant,
                                          width: 2),
                                      borderRadius: BorderRadius.circular(4),
                                    ),
                              isActive: index == currentPage,
                            )),
                    const Divider(height: 64),
                    Text('Custom builder', style: headlineStyle),
                    _PageView(
                        pages: 42,
                        initialPage: 21,
                        size: 44,
                        itemBuilder: (
                          BuildContext context,
                          int index,
                          int? currentPage,
                        ) => _Dot(
                              key: ValueKey(index),
                              shape: index.isEven
                                  ? BoxShape.circle
                                  : BoxShape.rectangle,
                              isActive: index == currentPage,
                              child: Center(
                                child: Text('$index',
                                    style: TextStyle(
                                        fontSize: 16,
                                        color: index == currentPage
                                            ? colorScheme.onPrimary
                                            : colorScheme
                                                .onSecondaryContainer)),
                              ),
                            )),
                    const Divider(height: 64),
                    Text('A million pages', style: headlineStyle),
                    const _PageView(
                      pages: 1000000,
                      initialPage: 500000,
                    ),
                    const Divider(height: 64),
                    Directionality(
                      textDirection: TextDirection.rtl,
                      child: Column(
                        children: [
                          Text('An RTL PageView', style: headlineStyle),
                          const _PageView(pages: 42, initialPage: 21),
                        ],
                      ),
                    ),
                  ],
                ),
              ),
            ),
          ),
        ),
      ),
    );
  }
}

class _PageView extends StatefulWidget {
  final int pages;
  final int? initialPage;
  final FaabulDotIndicatorItemBuilder? itemBuilder;
  final double size;

  const _PageView({
    required this.pages,
    this.initialPage,
    this.itemBuilder,
    this.size = 20.0,
  });

  [@override](/user/override)
  State<_PageView> createState() => __PageViewState();
}

class __PageViewState extends State<_PageView> {
  late final _controller = PageController(
      viewportFraction: 0.8, initialPage: widget.initialPage ?? 0);

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Column(
      mainAxisSize: MainAxisSize.min,
      children: [
        SizedBox(
          height: 300,
          child: PageView.builder(
            itemCount: widget.pages,
            itemBuilder: _buildPage,
            controller: _controller,
          ),
        ),
        FaabulPageIndicator(
          itemBuilder: widget.itemBuilder,
          itemSize: Size(widget.size, widget.size),
          itemCount: widget.pages,
          controller: _controller,
        ),
      ],
    );
  }

  Widget? _buildPage(BuildContext context, int index) {
    return Card(
      margin: const EdgeInsets.all(32),
      color: index.isEven ? Colors.red : Colors.blue,
      child: Center(
        child: Text(
          'Page $index',
          style: const TextStyle(fontSize: 32),
        ),
      ),
    );
  }
}

class _Dot extends StatelessWidget {
  final BoxShape shape;
  final Widget child;
  final bool isActive;
  const _Dot(
      {required super.key,
      required this.shape,
      required this.child,
      required this.isActive});

  [@override](/user/override)
  Widget build(BuildContext context) {
    final colorScheme = Theme.of(context).colorScheme;
    return SizedBox(
      width: 44,
      height: 44,
      child: Center(
          child: AnimatedContainer(
        duration: Durations.long2,
        curve: Curves.easeInOut,
        width: isActive ? 40 : 32,
        height: isActive ? 40 : 32,
        decoration: BoxDecoration(
          color:
              isActive ? colorScheme.primary : colorScheme.secondaryContainer,
          shape: shape,
        ),
        child: child,
      )),
    );
  }
}

更多关于Flutter页面指示器插件faabul_page_indicator的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter页面指示器插件faabul_page_indicator的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter项目中使用faabul_page_indicator插件的一个示例。faabul_page_indicator是一个流行的页面指示器插件,用于在分页视图中显示小圆点或其他样式的指示器。

首先,确保你已经在pubspec.yaml文件中添加了faabul_page_indicator依赖:

dependencies:
  flutter:
    sdk: flutter
  faabul_page_indicator: ^latest_version  # 请替换为最新版本号

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

接下来,在你的Dart文件中,你可以使用FaabulPageIndicator来创建一个页面指示器。下面是一个完整的示例,展示了如何结合PageViewFaabulPageIndicator来实现分页视图和指示器。

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Faabul Page Indicator Example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin {
  final PageController _pageController = PageController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Faabul Page Indicator Example'),
      ),
      body: Column(
        children: <Widget>[
          Expanded(
            child: PageView(
              controller: _pageController,
              children: <Widget>[
                Center(child: Text('Page 1')),
                Center(child: Text('Page 2')),
                Center(child: Text('Page 3')),
              ],
            ),
          ),
          FaabulPageIndicator(
            controller: _pageController,
            itemCount: 3,
            indicatorSpace: 10.0,
            indicatorColor: Colors.grey,
            activeIndicatorColor: Colors.blue,
            indicatorSize: 8.0,
            activeIndicatorSize: 12.0,
            shape: IndicatorShape.circle, // 可以选择其他形状,比如 IndicatorShape.roundRect
          ),
        ],
      ),
    );
  }

  @override
  void dispose() {
    _pageController.dispose();
    super.dispose();
  }
}

在这个示例中:

  1. 我们创建了一个PageView,它包含三个页面,每个页面都显示一个居中的文本。
  2. 我们使用FaabulPageIndicator作为页面指示器,并传递了PageController来控制分页视图。
  3. FaabulPageIndicator的各种属性,如indicatorColoractiveIndicatorColorindicatorSizeactiveIndicatorSize,允许我们自定义指示器的外观。
  4. indicatorSpace属性控制指示器之间的间距。
  5. shape属性允许我们选择指示器的形状。

确保你已经正确导入了faabul_page_indicator包,并根据需要调整属性和样式。这样,你就可以在你的Flutter应用中使用faabul_page_indicator来实现漂亮的页面指示器了。

回到顶部