Flutter粒子效果插件confetti的使用

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

Flutter粒子效果插件confetti的使用

Blast some confetti all over the screen and celebrate user achievements!

Confetti Screenshot

Demo

Getting Started

要使用这个插件,你需要在 pubspec.yaml 文件中添加 confetti 作为依赖项。

你可以通过查看示例代码快速开始。为了生成平台文件夹,请在示例文件夹中运行:

flutter create .

使用步骤

首先,你需要实例化一个 ConfettiController 变量,并传入一个 Duration 参数。ConfettiController 可以在 initState 方法中实例化并在 dispose 方法中销毁。

build 方法中返回一个 ConfettiWidget。唯一必需的属性是 ConfettiController

其他可设置的属性有:

  • blastDirectionality -> 枚举值,用于指定粒子发射方向。BlastDirectionality.explosive 将随机发射,不需要设置 blastDirectionBlastDirectionality.directional 需要设置 blastDirection 来指定发射方向。
  • blastDirection -> 径向值,用于确定粒子发射的方向,默认为 PI (180 度)。值为 PI 将向左发射。
  • emissionFrequency -> 介于 0 和 1 之间的值,表示每帧发射粒子的概率,默认为 0.02 (2%)。
  • numberOfParticles -> 每次发射的粒子数量,默认为 10。
  • shouldLoop -> 确定动画是否循环。
  • maxBlastForce -> 粒子初始5帧内的最大爆发力,默认为 20。
  • minBlastForce -> 粒子初始5帧内的最小爆发力,默认为 5。
  • displayTarget -> 如果为 true,则显示发射点的十字准心。
  • colors -> 提供颜色列表来手动设置粒子颜色。如果省略,则使用随机颜色。
  • strokeWidth -> 给画笔设置描边宽度,需要大于 0 才可见,默认为 0。
  • strokeColor -> 设置描边颜色,默认为黑色。
  • minimumSize -> 控制粒子的最小可能尺寸,默认为 Size(10,10)
  • maximumSize -> 控制粒子的最大可能尺寸,默认为 Size(100,100)
  • gravity -> 改变粒子下落速度,值介于 0 和 1 之间,默认为 0.1。
  • particleDrag -> 配置应用于粒子的阻力,默认为 0.05。
  • canvas -> 设置显示粒子的区域大小,默认为全屏。
  • createParticlePath -> 返回自定义 Path 的函数,默认返回矩形路径。

自定义 createParticlePath 示例

Path drawStar(Size size) {
  double degToRad(double deg) => deg * (pi / 180.0);

  const numberOfPoints = 5;
  final halfWidth = size.width / 2;
  final externalRadius = halfWidth;
  final internalRadius = halfWidth / 2.5;
  final degreesPerStep = degToRad(360 / numberOfPoints);
  final halfDegreesPerStep = degreesPerStep / 2;
  final path = Path();
  final fullAngle = degToRad(360);
  path.moveTo(size.width, halfWidth);

  for (double step = 0; step < fullAngle; step += degreesPerStep) {
    path.lineTo(halfWidth + externalRadius * cos(step),
        halfWidth + externalRadius * sin(step));
    path.lineTo(halfWidth + internalRadius * cos(step + halfDegreesPerStep),
        halfWidth + internalRadius * sin(step + halfDegreesPerStep));
  }
  path.close();
  return path;
}

完整示例代码

import 'dart:math';
import 'package:confetti/confetti.dart';
import 'package:flutter/material.dart';

void main() => runApp(const ConfettiSample());

class ConfettiSample extends StatelessWidget {
  const ConfettiSample({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) => MaterialApp(
        title: 'Confetti',
        home: Scaffold(
          backgroundColor: Colors.grey[900],
          body: MyApp(),
        ),
      );
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  late ConfettiController _controllerCenter;
  late ConfettiController _controllerCenterRight;
  late ConfettiController _controllerCenterLeft;
  late ConfettiController _controllerTopCenter;
  late ConfettiController _controllerBottomCenter;

  @override
  void initState() {
    super.initState();
    _controllerCenter =
        ConfettiController(duration: const Duration(seconds: 10));
    _controllerCenterRight =
        ConfettiController(duration: const Duration(seconds: 10));
    _controllerCenterLeft =
        ConfettiController(duration: const Duration(seconds: 10));
    _controllerTopCenter =
        ConfettiController(duration: const Duration(seconds: 10));
    _controllerBottomCenter =
        ConfettiController(duration: const Duration(seconds: 10));
  }

  @override
  void dispose() {
    _controllerCenter.dispose();
    _controllerCenterRight.dispose();
    _controllerCenterLeft.dispose();
    _controllerTopCenter.dispose();
    _controllerBottomCenter.dispose();

    super.dispose();
  }

  Path drawStar(Size size) {
    double degToRad(double deg) => deg * (pi / 180.0);

    const numberOfPoints = 5;
    final halfWidth = size.width / 2;
    final externalRadius = halfWidth;
    final internalRadius = halfWidth / 2.5;
    final degreesPerStep = degToRad(360 / numberOfPoints);
    final halfDegreesPerStep = degreesPerStep / 2;
    final path = Path();
    final fullAngle = degToRad(360);
    path.moveTo(size.width, halfWidth);

    for (double step = 0; step < fullAngle; step += degreesPerStep) {
      path.lineTo(halfWidth + externalRadius * cos(step),
          halfWidth + externalRadius * sin(step));
      path.lineTo(halfWidth + internalRadius * cos(step + halfDegreesPerStep),
          halfWidth + internalRadius * sin(step + halfDegreesPerStep));
    }
    path.close();
    return path;
  }

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Stack(
        children: [
          // CENTER -- Blast
          Align(
            alignment: Alignment.center,
            child: ConfettiWidget(
              confettiController: _controllerCenter,
              blastDirectionality: BlastDirectionality.explosive,
              shouldLoop: true,
              colors: const [
                Colors.green,
                Colors.blue,
                Colors.pink,
                Colors.orange,
                Colors.purple
              ],
              createParticlePath: drawStar,
            ),
          ),
          Align(
            alignment: Alignment.center,
            child: TextButton(
              onPressed: () {
                _controllerCenter.play();
              },
              child: _text('blast\nstars'),
            ),
          ),

          // CENTER RIGHT -- Emit left
          Align(
            alignment: Alignment.centerRight,
            child: ConfettiWidget(
              confettiController: _controllerCenterRight,
              blastDirection: pi,
              particleDrag: 0.05,
              emissionFrequency: 0.05,
              numberOfParticles: 20,
              gravity: 0.05,
              shouldLoop: false,
              colors: const [
                Colors.green,
                Colors.blue,
                Colors.pink
              ],
              strokeWidth: 1,
              strokeColor: Colors.white,
            ),
          ),
          Align(
            alignment: Alignment.centerRight,
            child: TextButton(
              onPressed: () {
                _controllerCenterRight.play();
              },
              child: _text('pump left'),
            ),
          ),

          // CENTER LEFT - Emit right
          Align(
            alignment: Alignment.centerLeft,
            child: ConfettiWidget(
              confettiController: _controllerCenterLeft,
              blastDirection: 0,
              emissionFrequency: 0.6,
              minimumSize: const Size(10, 10),
              maximumSize: const Size(50, 50),
              numberOfParticles: 1,
              gravity: 0.1,
            ),
          ),
          Align(
            alignment: Alignment.centerLeft,
            child: TextButton(
              onPressed: () {
                _controllerCenterLeft.play();
              },
              child: _text('singles'),
            ),
          ),

          // TOP CENTER - shoot down
          Align(
            alignment: Alignment.topCenter,
            child: ConfettiWidget(
              confettiController: _controllerTopCenter,
              blastDirection: pi / 2,
              maxBlastForce: 5,
              minBlastForce: 2,
              emissionFrequency: 0.05,
              numberOfParticles: 50,
              gravity: 1,
            ),
          ),
          Align(
            alignment: Alignment.topCenter,
            child: TextButton(
                onPressed: () {
                  _controllerTopCenter.play();
                },
                child: _text('goliath')),
          ),
          // BOTTOM CENTER - Shoot up
          Align(
            alignment: Alignment.bottomCenter,
            child: ConfettiWidget(
              confettiController: _controllerBottomCenter,
              blastDirection: -pi / 2,
              emissionFrequency: 0.01,
              numberOfParticles: 20,
              maxBlastForce: 100,
              minBlastForce: 80,
              gravity: 0.3,
            ),
          ),
          Align(
            alignment: Alignment.bottomCenter,
            child: TextButton(
              onPressed: () {
                _controllerBottomCenter.play();
              },
              child: _text('hard and infrequent'),
            ),
          ),
        ],
      ),
    );
  }

  Text _text(String text) => Text(
        text,
        style: const TextStyle(color: Colors.white, fontSize: 20),
      );
}

Enjoy the confetti!

注意:不要过度使用粒子数量。屏幕上的粒子越多,需要进行的计算就越多。尽管性能有所改进,但过多的粒子仍可能导致性能问题。请谨慎使用。


更多关于Flutter粒子效果插件confetti的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter粒子效果插件confetti的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter项目中使用confetti插件来创建粒子效果的示例代码。

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

dependencies:
  flutter:
    sdk: flutter
  confetti: ^0.6.0  # 请检查最新版本号

然后运行flutter pub get来获取依赖项。

接下来,你可以在你的Flutter应用中创建一个包含粒子效果的页面。以下是一个完整的示例代码,展示如何在点击按钮时触发粒子效果:

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

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

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

class ConfettiPage extends StatefulWidget {
  @override
  _ConfettiPageState createState() => _ConfettiPageState();
}

class _ConfettiPageState extends State<ConfettiPage> {
  final ConfettiController _confettiController = ConfettiController();

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Confetti Example'),
      ),
      body: Stack(
        children: [
          Center(
            child: ConfettiWidget(
              confettiController: _confettiController,
              blastDirectionality: BlastDirectionality.explosive,
              emissionFrequency: 0.02,
              numberOfParticles: 50,
              gravity: 0.1,
              colors: [
                Colors.redAccent,
                Colors.greenAccent,
                Colors.blueAccent,
                Colors.yellowAccent,
              ],
              shapes: [
                ConfettiShape.circle,
                ConfettiShape.square,
                ConfettiShape.triangle,
              ],
              blastCount: 1,
              // 可以在这里添加更多自定义参数
            ),
          ),
          Center(
            child: ElevatedButton(
              onPressed: () {
                _confettiController.addBurst(
                  count: 100,
                  beginPosition: Offset.zero,
                  colors: [Colors.red, Colors.blue, Colors.green, Colors.yellow],
                  blastRadius: 10.0,
                );
              },
              child: Text('Trigger Confetti'),
            ),
          ),
        ],
      ),
    );
  }
}

在这个示例中:

  1. ConfettiController 用于控制粒子效果的播放。
  2. ConfettiWidget 是显示粒子效果的部件。你可以自定义它的许多属性,比如粒子的形状、颜色、数量、重力等。
  3. addBurst 方法用于在特定位置触发一次粒子爆发。在这个例子中,点击按钮时会触发一次爆发。

你可以根据需要调整这些参数来实现不同的粒子效果。希望这个示例对你有帮助!

回到顶部