如何使窗口小部件在动画中向下滑动?

时间:2019-04-17 19:27:20

标签: dart flutter flutter-layout flutter-animation

我想为小部件制作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文件的原因。

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

2 个答案:

答案 0 :(得分:1)

我从您对代码的描述中推断出,您希望能够创建从屏幕顶部向下滑动的吐司,并且希望能够在任何地方创建它。

您很幸运,颤振具有此功能! 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)。

您也可以直接使用覆盖项来执行此操作,但这绝对简单。

答案 1 :(得分:0)

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

这是StatefulWidget

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),
);