如何在 flutter 中做 widget 的下拉动画?

How to do widget slide down animation in flutter?

我想为小部件制作 slide-down 动画。我从互联网上看到了很多例子,但没有一个符合我的要求。这就是我需要的。下面是我制作的自定义小部件。

Widget Toast(String content, ToastType type) {
  return Column(
    children: <Widget>[
      Padding(
        padding: const EdgeInsets.all(50),
        child: Card(
          elevation: 10,
          shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5)),
          color: ToastColors[type.index],
          child: Padding(
            padding: const EdgeInsets.only(left: 15, right: 20, top: 10, bottom: 10),
            child: Row(
              mainAxisSize: MainAxisSize.min,
              children: <Widget>[
                ToastIcons[type.index],
                SizedBox(
                  width: 15,
                ),
                Flexible(
                  child: Text(
                    content,
                    style: TextStyle(
                      color: Colors.white,
                      fontWeight: FontWeight.w400,
                    ),
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
    ],
  );
}

这是吐司布局。我希望可以从应用程序内的任何地方访问它。这就是为什么我为此创建了单独的 dart 文件。

我想要什么? 显示小部件时,我希望 toast 布局向下滑动。我不想循环播放或反转动画。动画完成后,小部件必须保持在结束位置静止。

根据您对代码的描述,我推断您希望能够创建一个从屏幕顶部向下滑动的 toast,并且您希望能够从任何地方创建它。

你很幸运,flutter 有一个功能! showGeneralDialog 就是您要找的。

这是一个例子:

import 'package:flutter/material.dart';

main() => runApp(TheApp());

class TheApp extends StatefulWidget {
  @override
  _TheAppState createState() => _TheAppState();
}

class _TheAppState extends State<TheApp> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        floatingActionButton: Builder(
          builder: (context) {
            return FloatingActionButton(
              child: Icon(
                Icons.add,
              ),
              onPressed: () {
                bool wasCompleted = false;
                showGeneralDialog(
                  context: context,
                  barrierDismissible: true,
                  transitionDuration: Duration(milliseconds: 500),
                  barrierLabel: MaterialLocalizations.of(context).dialogLabel,
                  barrierColor: Colors.black.withOpacity(0.5),
                  pageBuilder: (context, _, __) {
                    return TheToast();
                  },
                  transitionBuilder: (context, animation, secondaryAnimation, child) {
                    if (animation.status == AnimationStatus.completed) {
                      wasCompleted = true;
                    }

                    if (wasCompleted) {
                      return FadeTransition(
                        opacity: animation,
                        child: child,
                      );
                    } else {
                      return SlideTransition(
                        position: CurvedAnimation(
                          parent: animation,
                          curve: Curves.easeOut,
                        ).drive(Tween<Offset>(begin: Offset(0, -1.0), end: Offset.zero)),
                        child: child,
                      );
                    }
                  },
                );
              },
            );
          },
        ),
        body: Container(),
      ),
    );
  }
}

class TheToast extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Card(
        color: Colors.white,
        child: Padding(
          padding: EdgeInsets.all(10),
          child: Text(
            "I'm a Toast",
            style: TextStyle(color: Colors.black),
          ),
        ),
      ),
    );
  }
}

您可以创建类似于 showGeneralDialog(也许是 showToast)的自己的函数,并使用适当的文本调用它。我还让吐司在动画播放后淡出;如果你只是想让它向上滑动,那就更简单了,你可以去掉那部分转换逻辑。我还让吐司在点击背景时消失,但您可以禁用它,而是在您希望隐藏对话框时调用 Navigator.pop(context)。

您也可以直接使用叠加条目执行此操作,但这绝对更简单。

Nvm。我想到了。首先,我创建了一个 StatefulWidget 并在 showToastWidget 函数中将其用作子项。

这里是StatefulWidgetclass

import 'package:flutter/material.dart';

class SlideToast extends StatefulWidget {
  final Widget _toast;

  SlideToast(this._toast);

  @override
  _SlideToastState createState() => _SlideToastState();
}

class _SlideToastState extends State<SlideToast> with TickerProviderStateMixin {
  AnimationController _controller;
  Animation<Offset> _offsetFloat;

  @override
  void initState() {
    super.initState();

    _controller = AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 350),
    );

    _offsetFloat =
        Tween(begin: Offset(0.0, -0.03), end: Offset.zero).animate(
      CurvedAnimation(
        parent: _controller,
        curve: Curves.fastOutSlowIn,
      ),
    );

    _offsetFloat.addListener(() {
      setState(() {});
    });

    _controller.forward();
  }

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

  @override
  Widget build(BuildContext context) {
    return SlideTransition(
      position: _offsetFloat,
      child: widget._toast,
    );
  }
}

必需 functionenumlist

enum ToastType { Info, Warning, Success, Error }

const List<Color> ToastColors = [
  Colors.blue,
  Colors.orange,
  Colors.green,
  Colors.redAccent
];

const List<Icon> ToastIcons = [
  Icon(
    Icons.info,
    color: Colors.white,
  ),
  Icon(
    Icons.info,
    color: Colors.white,
  ),
  Icon(
    Icons.check_circle,
    color: Colors.white,
  ),
  Icon(
    Icons.error,
    color: Colors.white,
  )
];

Widget Toast(String content, ToastType type) {
  return Column(
    children: <Widget>[
      Padding(
        padding: const EdgeInsets.only(top: 85),
        child: Card(
          elevation: 10,
          shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5)),
          color: ToastColors[type.index],
          child: Padding(
            padding:
                const EdgeInsets.only(left: 15, right: 20, top: 10, bottom: 10),
            child: Row(
              mainAxisSize: MainAxisSize.min,
              children: <Widget>[
                ToastIcons[type.index],
                SizedBox(
                  width: 15,
                ),
                Flexible(
                  child: Text(
                    content,
                    style: TextStyle(
                      color: Colors.white,
                      fontWeight: FontWeight.w400,
                    ),
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
    ],
  );
}

最后这样调用showToastWidget

showToastWidget(
   Toast('Hello World!!!', ToastType.Warning),
   duration: Duration(seconds: 1),
);