简体   繁体   中英

How to do widget slide down animation in flutter?

I want to do a slide-down animation for a widget. I've seen a lot of examples from the internet but nothing meets my requirements. Here is what I need. Below is a custom widget I made.

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

It's a toast layout. I want this to be accessible from anywhere within the app. That's why I've created separate dart file for this.

What I want? When the widget is shown, I want the toast layout to slide down. I don't want to loop or reverse the animation. After the animation is completed, the widget must stay still in the end position.

I'm extrapolating from your description of your code that you want to be able to create a toast that slides down from the top of the screen, and that you want to be able to create it from anywhere.

You're in luck, flutter has a function for that! showGeneralDialog is what you're looking for.

Here's an example:

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

You could make your own function similar to showGeneralDialog (maybe showToast) and call that with the appropriate text. I've also made the toast fade out after the animation; if you just want it to slide back up that's even simpler and you can get rid of that part of the transition logic. I've also made the toast disappear when the background is tapped but you could disable that and instead call Navigator.pop(context) when you want the dialog to be hidden instead.

You could also do this directly with Overlay entries but this is definitely simpler.

Nvm. I figured it out. First I created a StatefulWidget and used it as a child in showToastWidget function.

Here is the StatefulWidget class

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

Required function , enum , list

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

Finally call showToastWidget like this

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM