如何在Flutter中制作Alert Dialog摇动动画
How to make Alert Dialog shaking animation in Flutter
我想像这样摇动警告对话框:(不仅是文本,还有整个弹出对话框)
https://www.youtube.com/watch?v=IaHMoifUBSw
如何在用户单击按钮时摇动整个警告对话框?
这可以通过 AnimatedBuilder
和 Transform
小部件来完成。使用 dart:math
中的 sin
函数将 0.0
到 1.0
之间的 AnimationController
值映射为具有所需振幅的平滑正弦波。可以在 AnimationController
本身中使用 duration
直接指定周期。
要启动动画,您可以调用 controller.repeat()
使其无限期地 运行,直到您调用 controller.stop()
,或者您可以使用 controller.forward()
来 运行一次。
让它摇晃3次然后停止,比如你可以这样做:
onPressed: () async {
await _controller.forward(from: 0.0);
await _controller.forward(from: 0.0);
await _controller.forward(from: 0.0);
},
实际效果如下(请注意 GIF 的帧率限制):
下面附上了完整的源代码供您用作起点。您可以调整duration
和distance
来改变摇动动画的强度:
import 'dart:math';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Test(),
);
}
}
class Test extends StatelessWidget {
const Test({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Shaking Dialog Demo')),
body: Center(
child: ElevatedButton(
child: Text('Show Dialog'),
onPressed: () {
showDialog(
context: context,
builder: (_) => ShakeableDialog(),
);
},
),
),
);
}
}
class ShakeableDialog extends StatefulWidget {
final Duration duration; // how fast to shake
final double distance; // how far to shake
const ShakeableDialog({
Key? key,
this.duration = const Duration(milliseconds: 300),
this.distance = 24.0,
}) : super(key: key);
@override
_ShakeableDialogState createState() => _ShakeableDialogState();
}
class _ShakeableDialogState extends State<ShakeableDialog>
with SingleTickerProviderStateMixin {
late final _controller = AnimationController(
vsync: this,
duration: widget.duration,
);
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _controller,
builder: (BuildContext context, Widget? child) {
final dx = sin(_controller.value * 2 * pi) * widget.distance;
return Transform.translate(
offset: Offset(dx, 0),
child: child,
);
},
child: AlertDialog(
title: Text('Alert Dialog Title'),
content: Text('Try these buttons!'),
actions: [
TextButton(
child: Text('SHAKE 3 TIMES'),
onPressed: () async {
await _controller.forward(from: 0.0);
await _controller.forward(from: 0.0);
await _controller.forward(from: 0.0);
},
),
TextButton(
child: Text('KEEP SHAKING'),
onPressed: () => _controller.repeat(),
),
TextButton(
child: Text('STOP SHAKING'),
onPressed: () => _controller.stop(),
),
TextButton(
child: Text('CLOSE'),
onPressed: () => Navigator.of(context).pop(),
),
],
),
);
}
}
我想像这样摇动警告对话框:(不仅是文本,还有整个弹出对话框)
https://www.youtube.com/watch?v=IaHMoifUBSw
如何在用户单击按钮时摇动整个警告对话框?
这可以通过 AnimatedBuilder
和 Transform
小部件来完成。使用 dart:math
中的 sin
函数将 0.0
到 1.0
之间的 AnimationController
值映射为具有所需振幅的平滑正弦波。可以在 AnimationController
本身中使用 duration
直接指定周期。
要启动动画,您可以调用 controller.repeat()
使其无限期地 运行,直到您调用 controller.stop()
,或者您可以使用 controller.forward()
来 运行一次。
让它摇晃3次然后停止,比如你可以这样做:
onPressed: () async {
await _controller.forward(from: 0.0);
await _controller.forward(from: 0.0);
await _controller.forward(from: 0.0);
},
实际效果如下(请注意 GIF 的帧率限制):
下面附上了完整的源代码供您用作起点。您可以调整duration
和distance
来改变摇动动画的强度:
import 'dart:math';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Test(),
);
}
}
class Test extends StatelessWidget {
const Test({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Shaking Dialog Demo')),
body: Center(
child: ElevatedButton(
child: Text('Show Dialog'),
onPressed: () {
showDialog(
context: context,
builder: (_) => ShakeableDialog(),
);
},
),
),
);
}
}
class ShakeableDialog extends StatefulWidget {
final Duration duration; // how fast to shake
final double distance; // how far to shake
const ShakeableDialog({
Key? key,
this.duration = const Duration(milliseconds: 300),
this.distance = 24.0,
}) : super(key: key);
@override
_ShakeableDialogState createState() => _ShakeableDialogState();
}
class _ShakeableDialogState extends State<ShakeableDialog>
with SingleTickerProviderStateMixin {
late final _controller = AnimationController(
vsync: this,
duration: widget.duration,
);
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _controller,
builder: (BuildContext context, Widget? child) {
final dx = sin(_controller.value * 2 * pi) * widget.distance;
return Transform.translate(
offset: Offset(dx, 0),
child: child,
);
},
child: AlertDialog(
title: Text('Alert Dialog Title'),
content: Text('Try these buttons!'),
actions: [
TextButton(
child: Text('SHAKE 3 TIMES'),
onPressed: () async {
await _controller.forward(from: 0.0);
await _controller.forward(from: 0.0);
await _controller.forward(from: 0.0);
},
),
TextButton(
child: Text('KEEP SHAKING'),
onPressed: () => _controller.repeat(),
),
TextButton(
child: Text('STOP SHAKING'),
onPressed: () => _controller.stop(),
),
TextButton(
child: Text('CLOSE'),
onPressed: () => Navigator.of(context).pop(),
),
],
),
);
}
}