Flutter优雅弹簧动画插件elegant_spring_animation的使用

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

Flutter优雅弹簧动画插件elegant_spring_animation的使用

整理后的内容

标题: Flutter优雅弹簧动画插件elegant_spring_animation的使用
内容:

  • 简介: 使用弹簧物理原理创建自然流畅的动画。

  • 示例链接: WASM | JavaScript

  • 基本用法: 添加依赖 elegant_spring_animation: ^2.0.2 到 pubspec.yaml 文件中。

  • 代码示例:

    late AnimationController animationController;
    final ElegantSpring curve = ElegantSpring.smooth;
    
    [@override](/user/override)
    void initState() {
      super.initState();
      animationController = AnimationController(vsync: this, duration: curve.recommendedDuration);
    }
    
    ScaleTransition(
      scale: CurvedAnimation(parent: animationController, curve: curve, reverseCurve: curve.flipped),
      child: ...,
    )
    
    AnimatedScale(
      scale: condition ? 0.5 : 1.0,
      duration: curve.recommendedDuration,
      curve: curve,
      child: ...,
    )
    
  • 自定义弹跳: 可以通过设置 bounce 参数来调整动画的弹跳效果。 默认值为 0 (无弹跳)。

    final ElegantSpring curve = ElegantSpring(bounce: 0.25);
    
  • 预设曲线: 提供了五种预设曲线:

    • ElegantSpring.smooth: 无弹跳,平滑地到达最终位置。
    • ElegantSpring.gentleBounce: 很轻微的弹跳。
    • ElegantSpring.mediumBounce: 明显的弹跳,但不令人分心。
    • ElegantSpring.strongBounce: 强烈的弹跳。
    • ElegantSpring.maximumBounce: 最大的弹跳,适合游戏和有趣的UI。

示例代码

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

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky);
  runApp(MyApp());
}

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

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Elegant Spring Animation Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple, brightness: Brightness.light),
        useMaterial3: true,
      ),
      darkTheme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple, brightness: Brightness.dark),
        useMaterial3: true,
        brightness: Brightness.dark,
      ),
      themeMode: ThemeMode.dark,
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  [@override](/user/override)
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin {
  late double _kBounce = 0.0;
  late int _kDuration = _elegantCurve.recommendedDuration.inMilliseconds;
  late final AnimationController _animationController = AnimationController(vsync: this, duration: Duration(milliseconds: _kDuration));
  late CurvedAnimation _animation =
      CurvedAnimation(parent: _animationController, curve: _elegantCurve, reverseCurve: _elegantCurve.flipped);
  late ElegantSpring _elegantCurve = ElegantSpring(bounce: _kBounce);

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

  [@override](/user/override)
  Widget build(BuildContext context) {
    final double maxWidth = max(MediaQuery.sizeOf(context).height / 2, MediaQuery.sizeOf(context).width / 2);

    _animation = CurvedAnimation(parent: _animationController, curve: _elegantCurve, reverseCurve: _elegantCurve.flipped);

    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: const Text(
          'Elegant Spring Animation Demo',
          style: TextStyle(color: Colors.white),
        ),
        centerTitle: true,
      ),
      body: FractionallySizedBox(
        widthFactor: 1.0,
        child: Wrap(
          //crossAxisAlignment: WrapCrossAlignment.center,
          runAlignment: WrapAlignment.center,
          alignment: WrapAlignment.center,
          children: [
            SizedBox(
              width: maxWidth,
              child: AspectRatio(
                aspectRatio: 1,
                child: FractionallySizedBox(
                  //widthFactor: 0.7,
                  heightFactor: 0.7,
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    mainAxisSize: MainAxisSize.min,
                    children: [
                      Text(
                        'Duration: $_kDuration ms',
                        style: Theme.of(context).textTheme.headlineSmall,
                      ),
                      Slider(
                        divisions: 198,
                        min: 100.0,
                        max: 10000.0,
                        value: _kDuration.toDouble(),
                        onChanged: (double val) {
                          setState(() {
                            _kDuration = val.toInt();
                          });
                        },
                      ),
                      Text(
                        'Bounce: $_kBounce',
                        style: Theme.of(context).textTheme.headlineSmall,
                      ),
                      Slider(
                        divisions: 20,
                        min: 0.0,
                        max: 1.0,
                        value: _kBounce,
                        onChanged: (double val) {
                          setState(() {
                            _kBounce = double.parse(val.toStringAsFixed(2));
                            _elegantCurve = ElegantSpring(bounce: _kBounce);
                            _kDuration = _elegantCurve.recommendedDuration.inMilliseconds;
                          });
                        },
                      ),
                    ],
                  ),
                ),
              ),
            ),
            SizedBox(
              width: maxWidth,
              child: AspectRatio(
                aspectRatio: 1,
                child: Align(
                  alignment: const Alignment(0.0, -0.5),
                  child: FractionallySizedBox(
                    widthFactor: 0.5,
                    heightFactor: 0.5,
                    child: ScaleTransition(
                      scale: _animation.drive(Tween<double>(begin: 1.0, end: 0.2)),
                      child: RotationTransition(
                        turns: _animation.drive(Tween<double>(begin: 0.0, end: 0.5)),
                        child: Container(
                          decoration: BoxDecoration(
                            borderRadius: BorderRadius.circular(20.0),
                            color: Theme.of(context).colorScheme.primary,
                          ),
                        ),
                      ),
                    ),
                  ),
                ),
              ),
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton.extended(
        onPressed: _isAnimating
            ? null
            : () async {
              setState(() {
                _animationController.duration = Duration(milliseconds: _kDuration);
                _isAnimating = true;
              });

              if (_animationController.isDismissed) {
                await _animationController.forward();
              } else {
                await _animationController.reverse();
              }

              setState(() {
                _isAnimating = false;
              });
            },
        backgroundColor: _isAnimating ? Theme.of(context).colorScheme.secondaryContainer : Theme.of(context).colorScheme.inversePrimary,
        foregroundColor: _isAnimating ? Colors.white38 : Colors.white,
        label: const Text('Run'),
        icon: const Icon(Icons.play_circle_outline_rounded),
      ),
      floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
    );
  }

  late bool _isAnimating = false;
}

更多关于Flutter优雅弹簧动画插件elegant_spring_animation的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter优雅弹簧动画插件elegant_spring_animation的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter中使用elegant_spring_animation插件来实现优雅弹簧动画的代码示例。

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

dependencies:
  flutter:
    sdk: flutter
  elegant_spring_animation: ^2.0.0  # 请检查最新版本号

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

接下来是一个完整的示例代码,展示如何使用elegant_spring_animation来实现一个简单的弹簧动画:

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Elegant Spring Animation Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

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

class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late ElegantAnimation _animation;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: const Duration(seconds: 2),
      vsync: this,
    )..repeat(reverse: true);

    _animation = ElegantAnimation(
      controller: _controller,
      tween: Tween<double>(begin: 0, end: 300),
      curve: Curves.easeInOut,
      overshootClamp: 0.2,
      period: 0.4,
    )..addListener(() {
        setState(() {});
      });
  }

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Elegant Spring Animation Demo'),
      ),
      body: Center(
        child: AnimatedBuilder(
          animation: _animation,
          child: Container(
            width: 100,
            height: 100,
            color: Colors.blue,
          ),
          builder: (_, child, animationValue) {
            return Transform.translate(
              offset: Offset(0, animationValue.value),
              child: child,
            );
          },
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          _controller.reset();
          _controller.forward();
        },
        tooltip: 'Restart Animation',
        child: Icon(Icons.replay),
      ),
    );
  }
}

代码解释:

  1. 依赖导入:首先导入flutterelegant_spring_animation包。
  2. 创建主应用MyApp类定义了应用的主题和主页。
  3. 主页MyHomePage是一个有状态的小部件,用于控制动画。
  4. 动画控制器:在initState方法中,我们创建了一个AnimationController,并设置它的持续时间为2秒。vsync: this确保动画与屏幕刷新同步。
  5. ElegantAnimation:创建ElegantAnimation实例,设置动画的开始和结束值、曲线、过冲夹持和周期。
  6. 动画监听:通过addListener方法在动画值变化时调用setState来更新UI。
  7. 动画构建:使用AnimatedBuilder根据动画值构建UI,这里我们实现了一个简单的垂直平移动画。
  8. 重置和重启动画:通过点击浮动操作按钮可以重置并重新启动动画。

这个示例展示了如何使用elegant_spring_animation插件来实现一个基本的弹簧动画效果。你可以根据需要调整动画参数,以实现更复杂和多样的动画效果。

回到顶部