如何在 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
函数中将其用作子项。
这里是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,
);
}
}
必需 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,
),
),
),
],
),
),
),
),
],
);
}
最后这样调用showToastWidget
showToastWidget(
Toast('Hello World!!!', ToastType.Warning),
duration: Duration(seconds: 1),
);
我想为小部件制作 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
函数中将其用作子项。
这里是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,
);
}
}
必需 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,
),
),
),
],
),
),
),
),
],
);
}
最后这样调用showToastWidget
showToastWidget(
Toast('Hello World!!!', ToastType.Warning),
duration: Duration(seconds: 1),
);