Flutter动画堆栈插件animated_stack的使用

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

Flutter动画堆栈插件 animated_stack 的使用

animated_stack 是一个用于创建自定义可堆叠页面的Flutter插件,特别适用于侧边菜单按钮、分享按钮、消息发送、关于页面等场景。本文将详细介绍如何使用这个插件,并提供完整的示例代码。

功能概述

通过 animated_stack,你可以轻松实现带有动画效果的堆叠页面。以下是一些主要功能:

  • 自定义背景和前景部件
  • 支持右侧面板(Column)和底部面板(Row)
  • 可调整滑动动画的高度和宽度
  • 设置FAB(Floating Action Button)图标及其颜色
  • 自定义动画时长和曲线

快速开始

首先,你需要创建前景和背景部件。下面是一个简单的例子,展示了最低要求的配置:

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

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Animated Stack Demo',
      theme: ThemeData(
        splashColor: Colors.transparent,
        highlightColor: Colors.transparent,
      ),
      home: AnimatedStack(
        backgroundColor: Colors.white,
        fabBackgroundColor: Colors.black,
        foregroundWidget: Container(), // 主页内容
        columnWidget: Column(), // 右侧部件,建议使用Column
        bottomWidget: Row(), // 底部部件,建议使用Row
      ),
    );
  }
}

完整功能列表

以下是你可以自定义的所有属性:

AnimatedStack(
    backgroundColor: ...,     // 背景容器颜色
    foregroundWidget: ...,    // 前景容器颜色
    
    columnWidget: ...,        // 右侧部件,建议使用Column
    bottomWidget: ...,        // 底部部件,建议使用Row
    
    scaleHeight: 100,         // 滑动动画高度,默认为60
    scaleWidth: 100,          // 滑动动画宽度,默认为60
    
    buttonIcon: ...,          // FAB图标 (IconData)
    fabIconColor: ...,        // FAB图标颜色
    animateButton: false,     // 是否启用按钮动画
    fabBackgroundColor: ...,  // FAB背景颜色
    
    slideAnimationDuration: ..., // 滑动动画时长,默认为800毫秒
    buttonAnimationDuration: ...,// 按钮动画时长,默认为240毫秒
    
    openAnimationCurve: ...,    // 打开动画曲线,默认为ElasticOutCurve(0.9)
    closeAnimationCurve: ...,   // 关闭动画曲线,默认为ElasticInCurve(0.9),
);

示例Demo

下面是一个更详细的示例,包含了前景、右侧和底部部件的具体实现:

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

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Animated Stack Demo',
      theme: ThemeData(
        splashColor: Colors.transparent,
        highlightColor: Colors.transparent,
      ),
      home: AnimatedStack(
        backgroundColor: Color(0xff321B4A),
        fabBackgroundColor: Color(0xffEB456F),
        foregroundWidget: Container(
          decoration: BoxDecoration(
            color: Color(0xff56377C),
            boxShadow: <BoxShadow>[
              BoxShadow(
                color: Colors.black26,
                blurRadius: 30,
                offset: Offset(4, 4),
              ),
            ],
            borderRadius: BorderRadius.all(
              Radius.circular(40),
            ),
          ),
          child: ListView.builder(
            itemCount: 5,
            itemBuilder: (context, index) {
              return _ItemPlaceholder();
            },
          ),
        ),
        columnWidget: Column(
          children: <Widget>[
            _IconTile(
              width: 100,
              height: 60,
              iconData: Icons.share,
            ),
            SizedBox(height: 20),
            _IconTile(
              width: 60,
              height: 60,
              iconData: Icons.image,
            ),
            SizedBox(height: 20),
            _IconTile(
              width: 60,
              height: 60,
              iconData: Icons.camera_alt,
            ),
          ],
        ),
        bottomWidget: Container(
          decoration: BoxDecoration(
            color: Color(0xff645478),
            borderRadius: BorderRadius.all(
              Radius.circular(50),
            ),
          ),
          width: 260,
          height: 50,
        ),
      ),
    );
  }
}

class _IconTile extends StatelessWidget {
  final double width;
  final double height;
  final IconData iconData;

  const _IconTile({
    Key? key,
    required this.width,
    required this.height,
    required this.iconData,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      width: width,
      height: height,
      decoration: BoxDecoration(
        color: Color(0xff645478),
        borderRadius: BorderRadius.all(
          Radius.circular(15),
        ),
      ),
      child: Icon(
        iconData,
        color: Color(0xffAEA6B6),
      ),
    );
  }
}

class _ItemPlaceholder extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      padding: EdgeInsets.symmetric(horizontal: 15, vertical: 15),
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          ClipOval(
            child: Container(
              width: 60,
              height: 60,
              color: Color(0xff9783A9),
            ),
          ),
          SizedBox(width: 15),
          Expanded(
            child: Container(
              height: 120,
              decoration: BoxDecoration(
                color: Color(0xff6D528D),
                borderRadius: BorderRadius.only(
                  bottomLeft: Radius.circular(20),
                  bottomRight: Radius.circular(30),
                  topLeft: Radius.circular(30),
                  topRight: Radius.circular(20),
                ),
              ),
              child: Padding(
                padding: const EdgeInsets.symmetric(horizontal: 20),
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: <Widget>[
                    Container(
                      child: _RowPlaceholder(color: 0xffA597B4),
                      width: MediaQuery.of(context).size.width * 2 / 5,
                    ),
                    _RowPlaceholder(color: 0xff846CA1),
                    _RowPlaceholder(color: 0xff846CA1),
                  ],
                ),
              ),
            ),
          )
        ],
      ),
    );
  }
}

class _RowPlaceholder extends StatelessWidget {
  final int color;

  const _RowPlaceholder({Key? key, required this.color}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      height: 15,
      decoration: BoxDecoration(
        color: Color(color),
        borderRadius: BorderRadius.all(
          Radius.circular(20),
        ),
      ),
    );
  }
}

许可证

该插件遵循 MIT License。

希望以上内容对你有所帮助!如果有任何问题,请随时提问。


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

1 回复

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


当然,关于animated_stack插件在Flutter中的使用,这里是一个具体的代码案例来展示如何创建一个动画堆栈。animated_stack是一个第三方库,它扩展了Flutter内置的Stack小部件,允许在堆栈中的子项之间进行平滑的过渡动画。

首先,确保在你的pubspec.yaml文件中添加animated_stack依赖:

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

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

接下来是一个使用animated_stack的示例代码:

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Animated Stack Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        appBar: AppBar(
          title: Text('Animated Stack Demo'),
        ),
        body: AnimatedStackDemo(),
      ),
    );
  }
}

class AnimatedStackDemo extends StatefulWidget {
  @override
  _AnimatedStackDemoState createState() => _AnimatedStackDemoState();
}

class _AnimatedStackDemoState extends State<AnimatedStackDemo> 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 Center(
      child: AnimatedStack(
        alignment: Alignment.center,
        fit: StackFit.expand,
        crossAxisAlignment: CrossAxisAlignment.center,
        animation: _animation,
        children: [
          Positioned(
            child: Container(
              color: Colors.blue.withOpacity(0.5),
              width: double.infinity,
              height: double.infinity,
            ),
          ),
          AnimatedStackItem(
            animationValue: _animation.value,
            child: Container(
              color: Colors.red,
              width: 100,
              height: 100,
            ),
          ),
          AnimatedStackItem(
            animationValue: 1 - _animation.value,
            child: Container(
              color: Colors.green,
              width: 100,
              height: 100,
            ),
          ),
        ],
      ),
    );
  }
}

class AnimatedStackItem extends StatelessWidget {
  final double animationValue;
  final Widget child;

  const AnimatedStackItem({Key? key, required this.animationValue, required this.child}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Opacity(
      opacity: animationValue,
      child: child,
    );
  }
}

解释

  1. 依赖添加:在pubspec.yaml中添加animated_stack依赖。
  2. 动画控制:使用AnimationControllerTween来控制动画,这里动画持续2秒并反复进行。
  3. AnimatedStack:使用AnimatedStack来包裹子项。AnimatedStack接受一个animation参数,该参数控制堆栈中子项的动画。
  4. AnimatedStackItem:自定义一个AnimatedStackItem小部件,使用Opacity根据animationValue调整透明度,这里模拟堆栈中子项的淡入淡出效果。
  5. 布局:两个不同颜色的容器作为堆栈的子项,通过动画控制它们的透明度变化。

注意:由于animated_stack库本身可能具有更多的功能和配置选项,建议查阅其官方文档以获取更多详细信息和高级用法。如果你发现Flutter官方仓库或社区有更推荐的动画堆栈解决方案,也可以考虑使用那些方法。

回到顶部