Flutter动画控制多子组件插件animated_multichild的使用

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

Flutter动画控制多子组件插件animated_multichild的使用

animated_multichild 是一个Flutter插件,用于创建具有动画效果的 ListViewGridViewRowColumn。通过这个插件,你可以轻松地为多个子组件添加动画效果,而无需手动编写复杂的动画代码。

展示

以下是 animated_multichild 插件在不同布局中的动画效果展示:

Row Column Grid List
Row Column Grid List

开始使用

  1. 添加依赖

    pubspec.yaml 文件中添加 animated_multichild 依赖:

    dependencies:
      animated_multichild: ^0.0.2
    

    或者,你可以在终端中使用以下命令来安装:

    flutter pub add animated_multichild
    
  2. 导入包

    在你的 Dart 代码中导入 animated_multichild 包:

    import 'package:animated_multichild/animated_multichild.dart';
    

使用示例

1. AnimatedListView

你可以将普通的 ListView 替换为 AnimatedListView,并使用 builder 构造函数来构建带有动画效果的列表项。以下是一个简单的 AnimatedListView 示例:

AnimatedListView.builder(
  itemBuilder: (BuildContext context, int index) {
    return const SizedBox(
      width: double.infinity,
      height: 100,
      child: Card(
        margin: EdgeInsets.all(8),
        elevation: 4,
      ),
    );
  },
  itemCount: 16,
)
2. 自定义过渡效果

你可以通过 transitionBuilder 属性来自定义动画效果。例如,创建一个淡入效果:

AnimatedListView.builder(
  transitionBuilder: (context, animation, child) {
    return FadeTransition(
      opacity: animation,
      child: child,
    );
  },
  // 其他代码
)

animated_multichild 提供了一些预定义的过渡效果,可以通过 Transitions 类来使用:

  • fadeIn
  • scale
  • slideInFromLeft
  • slideInFromRight
  • slideInFromBottom

你还可以使用 Transitions.combine 方法将多个过渡效果组合在一起。例如,结合缩放和淡入效果:

AnimatedListView.builder(
  transitionBuilder: Transitions.combine([Transitions.scale, Transitions.fadeIn]),
  // 其他代码
)
3. 指定动画时长和延迟

你可以通过 durationdelay 参数来自定义动画的持续时间和开始延迟。delay 参数是增量的,这意味着每个子组件的动画会依次开始,形成交错动画效果。如果你不希望有交错效果,可以将 delay 设置为 Duration.zero

AnimatedListView.builder(
  duration: const Duration(milliseconds: 375),
  delay: const Duration(milliseconds: 40),
  // 其他代码
)

如果你想自定义延迟而不使用交错效果,可以使用 CurvedAnimationInterval 来定义动画曲线。

4. 完整示例

以下是一个完整的示例,展示了如何使用 animated_multichild 创建带有动画效果的 ListViewColumnRowGridView

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

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

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

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Builder(builder: (context) {
        return Scaffold(
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                ElevatedButton(
                  key: const ValueKey('list'),
                  onPressed: () {
                    Navigator.of(context).push(
                      MaterialPageRoute(
                          builder: (_) => const ListViewPage(title: 'title')),
                    );
                  },
                  child: const Text('Animated ListView'),
                ),
                ElevatedButton(
                  key: const ValueKey('column'),
                  onPressed: () {
                    Navigator.of(context).push(
                      MaterialPageRoute(builder: (_) => const ColumnPage()),
                    );
                  },
                  child: const Text('Animated Column'),
                ),
                ElevatedButton(
                  key: const ValueKey('row'),
                  onPressed: () {
                    Navigator.of(context).push(
                      MaterialPageRoute(builder: (_) => const RowPage()),
                    );
                  },
                  child: const Text('Animated Row'),
                ),
                ElevatedButton(
                  key: const ValueKey('grid'),
                  onPressed: () {
                    Navigator.of(context).push(
                      MaterialPageRoute(builder: (_) => const GridPage()),
                    );
                  },
                  child: const Text('Animated Grid'),
                ),
              ],
            ),
          ),
        );
      }),
    );
  }
}

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

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.grey.shade100,
      appBar: AppBar(
        title: const Text('Animated Grid'),
      ),
      body: AnimatedGridView.count(
        padding: const EdgeInsets.all(16),
        transitionBuilder: Transitions.combine([Transitions.scale, Transitions.fadeIn]),
        curve: Curves.ease,
        crossAxisCount: 3,
        mainAxisSpacing: 8,
        crossAxisSpacing: 8,
        children: [
          for (int i = 0; i < 30; i++)
            const Card(
              elevation: 4,
            ),
        ],
      ),
    );
  }
}

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

  [@override](/user/override)
  Widget build(BuildContext context) {
    const gap = SizedBox(height: 16);

    return Scaffold(
      backgroundColor: Colors.grey.shade100,
      appBar: AppBar(
        title: const Text('Animated Column'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: AnimatedColumn(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: [
            const Expanded(
              child: Center(
                child: SizedBox.expand(
                  child: Card(
                    elevation: 4,
                  ),
                ),
              ),
            ),
            gap,
            Expanded(
              child: Row(
                children: const [
                  Expanded(
                    child: SizedBox(
                      height: double.maxFinite,
                      child: Card(elevation: 4),
                    ),
                  ),
                  Expanded(
                    child: SizedBox(
                      height: double.maxFinite,
                      child: Card(elevation: 4),
                    ),
                  ),
                ],
              ),
            ),
            gap,
            const Expanded(
              child: SizedBox(
                height: double.maxFinite,
                width: double.maxFinite,
                child: Card(elevation: 4),
              ),
            ),
            gap,
            Expanded(
              child: Row(
                children: const [
                  Expanded(
                    child: SizedBox(
                      height: double.maxFinite,
                      child: Card(elevation: 4),
                    ),
                  ),
                  Expanded(
                    child: SizedBox(
                      height: double.maxFinite,
                      child: Card(elevation: 4),
                    ),
                  ),
                  Expanded(
                    child: SizedBox(
                      height: double.maxFinite,
                      child: Card(elevation: 4),
                    ),
                  ),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}

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

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.grey.shade100,
      appBar: AppBar(
        title: const Text('Animated Row'),
      ),
      body: AnimatedRow(
        children: [
          for (int i = 0; i < 5; i++)
            const SizedBox(
              width: 64,
              height: 64,
              child: Card(
                margin: EdgeInsets.all(8),
                elevation: 4,
              ),
            ),
        ],
      ),
    );
  }
}

class ListViewPage extends StatefulWidget {
  const ListViewPage({super.key, required this.title});
  final String title;

  [@override](/user/override)
  State<ListViewPage> createState() => _ListViewPageState();
}

class _ListViewPageState extends State<ListViewPage> {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.grey.shade100,
      body: AnimatedListView.builder(
        transitionBuilder: (context, animation, child) {
          final position = Tween(begin: const Offset(0, 50), end: Offset.zero)
              .animate(animation);
          return Transform.translate(
            offset: position.value,
            child: Opacity(
              opacity: animation.value,
              child: child,
            ),
          );
        },
        delay: const Duration(milliseconds: 40),
        curve: Curves.ease,
        duration: const Duration(milliseconds: 375),
        itemBuilder: (BuildContext context, int index) {
          return const SizedBox(
            width: double.infinity,
            height: 100,
            child: Card(
              margin: EdgeInsets.all(8),
              elevation: 4,
            ),
          );
        },
        itemCount: 16,
      ),
    );
  }
}

更多关于Flutter动画控制多子组件插件animated_multichild的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter动画控制多子组件插件animated_multichild的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何使用 animated_multichild 插件来控制 Flutter 中多个子组件动画的示例代码。这个插件允许你通过动画控制器同时管理多个子组件的动画状态。

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

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

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

接下来是一个示例代码,展示了如何使用 animated_multichild 来控制多个子组件的动画:

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: AnimatedMultiChildDemo(),
    );
  }
}

class AnimatedMultiChildDemo extends StatefulWidget {
  @override
  _AnimatedMultiChildDemoState createState() => _AnimatedMultiChildDemoState();
}

class _AnimatedMultiChildDemoState extends State<AnimatedMultiChildDemo> with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation<double> _animation;

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

    _animation = Tween<double>(begin: 0, end: 1).animate(_controller);
  }

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('AnimatedMultiChild Demo'),
      ),
      body: Center(
        child: AnimatedMultiChild(
          animation: _animation,
          children: [
            AnimatedChild(
              child: Container(
                width: 100,
                height: 100,
                color: Colors.red,
                child: Center(
                  child: Text(
                    'Child 1',
                    style: TextStyle(color: Colors.white),
                  ),
                ),
              ),
              curve: Curves.easeInOutQuad,
              animationBuilder: (animation, child) {
                return Transform.scale(
                  scale: animation.value,
                  child: child,
                );
              },
            ),
            AnimatedChild(
              child: Container(
                width: 100,
                height: 100,
                color: Colors.blue,
                child: Center(
                  child: Text(
                    'Child 2',
                    style: TextStyle(color: Colors.white),
                  ),
                ),
              ),
              curve: Curves.easeInOutCubic,
              animationBuilder: (animation, child) {
                return Transform.rotate(
                  angle: animation.value * 2.0 * 3.141592653589793, // 360 degrees
                  child: child,
                );
              },
            ),
            AnimatedChild(
              child: Container(
                width: 100,
                height: 100,
                color: Colors.green,
                child: Center(
                  child: Text(
                    'Child 3',
                    style: TextStyle(color: Colors.white),
                  ),
                ),
              ),
              curve: Curves.easeInOutQuart,
              animationBuilder: (animation, child) {
                return Transform.translate(
                  offset: Offset(animation.value * 50 - 25, animation.value * 50 - 25), // Moves between -25 and 25
                  child: child,
                );
              },
            ),
          ],
        ),
      ),
    );
  }
}

在这个示例中:

  1. 我们创建了一个 AnimatedMultiChild 组件,它接受一个动画控制器 _animation 和多个 AnimatedChild 子组件。
  2. 每个 AnimatedChild 组件接受一个 child 组件,一个 curve 曲线,以及一个 animationBuilder 函数,用于构建动画效果。
  3. animationBuilder 函数使用动画值来变换子组件(例如缩放、旋转和平移)。

这样,你就可以通过单一的动画控制器 _controller 来控制多个子组件的动画效果了。

回到顶部