我是新手,我试图创建一个UI,其中有一个卡片组和一个显示的卡片。每当用户在卡片组上按一下时,我都希望显示新的卡片(使用带有“定位”小部件的翻转和移动动画)。
问题是,我无法理解每次创建窗口小部件时如何使动画出现。
我试图使动画在我创建的小部件的初始化状态下进行,但这似乎不起作用。
这是应用程序小部件树:
class _DeckState extends State<Deck> with TickerProviderStateMixin {
List<MyCard> _cards= <MyCard>[];
@override
void initState() {
super.initState();
_cards.insert(0, MyCard());
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("NLP Deck"),
),
body: Stack(
alignment: Alignment.center,
children: <Widget>[
Container(),
_cards[0],
Positioned(
top: 40.0,
child: GestureDetector(
onTap: PressedDeck,
child: Container(
width: 100.0,
height: 128.0,
decoration: BoxDecoration(color: Colors.brown),
),
),
),
],
),
);
}
void PressedDeck() {
setState(() {
_cards.insert(0, new MyCard());
});
}
}
这是我创建的Card小部件(使用Container代表卡片和卡片组):
class _CardState extends State<MyCard> with TickerProviderStateMixin {
AnimationController animController;
Animation flipAnimation;
Animation positionAnimation;
@override
void initState() {
super.initState();
animController = new AnimationController(
vsync: this, duration: Duration(milliseconds: 1000));
flipAnimation = Tween<double>(begin: 1.0, end: 0).animate(animController);
positionAnimation =
Tween<double>(begin: 40.0, end: 240.0).animate(animController);
animController.forward();
}
@override
Widget build(BuildContext context) {
return PositionTransition(
position: positionAnimation,
flip: flipAnimation,
);
}
@override
void dispose() {
animController.dispose();
super.dispose();
}
}
class PositionTransition extends AnimatedWidget {
PositionTransition({
@required Animation<double> position,
@required this.flip,
}) : super(listenable: position);
final Animation<double> flip;
@override
Widget build(BuildContext context) {
final position = super.listenable as Animation<double>;
return Positioned(
top: position.value,
child: Transform(
alignment: FractionalOffset.center,
transform: Matrix4.rotationX(math.pi * flip.value),
child: flip.value >= 0.5
? Container(
width: 100,
height: 128,
decoration: BoxDecoration(color: Colors.deepOrange),
)
: Container(
width: 100,
height: 128,
decoration: BoxDecoration(color: Colors.amber),
),
),
);
}
}
谢谢!
答案 0 :(得分:2)
您可以在下面复制粘贴运行完整代码
您可以在animController.reset()
中呼叫forward()
和didUpdateWidget
出于演示目的,我将动画持续时间更改为3秒
有关详细信息,您可以参考https://medium.com/sk-geek/flutter-experiment-to-trigger-animation-when-parent-setstate-84e949530b64
代码段
@override
void didUpdateWidget(MyCard oldWidget) {
animController.reset();
animController.forward();
super.didUpdateWidget(oldWidget);
}
工作演示
完整代码
import 'package:flutter/material.dart';
import 'dart:math' as math;
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Deck(),
);
}
}
class Deck extends StatefulWidget {
@override
_DeckState createState() => _DeckState();
}
class _DeckState extends State<Deck> with TickerProviderStateMixin {
List<MyCard> _cards = <MyCard>[];
@override
void initState() {
super.initState();
_cards.insert(0, MyCard());
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("NLP Deck"),
),
body: Stack(
alignment: Alignment.center,
children: <Widget>[
Container(),
_cards[0],
Positioned(
top: 40.0,
child: GestureDetector(
onTap: PressedDeck,
child: Container(
width: 100.0,
height: 128.0,
decoration: BoxDecoration(color: Colors.brown),
),
),
),
],
),
);
}
void PressedDeck() {
print("PressedDeck");
setState(() {
_cards.insert(0, new MyCard());
});
print("cards length ${_cards.length}");
}
}
class MyCard extends StatefulWidget {
@override
_MyCardState createState() => _MyCardState();
}
class _MyCardState extends State<MyCard> with TickerProviderStateMixin {
AnimationController animController;
Animation flipAnimation;
Animation positionAnimation;
@override
void initState() {
print("My card init State");
super.initState();
animController =
new AnimationController(vsync: this, duration: Duration(seconds: 3));
flipAnimation = Tween<double>(begin: 1.0, end: 0).animate(animController);
positionAnimation =
Tween<double>(begin: 40.0, end: 240.0).animate(animController);
animController.forward();
}
@override
void didUpdateWidget(MyCard oldWidget) {
animController.reset();
animController.forward();
super.didUpdateWidget(oldWidget);
}
@override
Widget build(BuildContext context) {
return PositionTransition(
position: positionAnimation,
flip: flipAnimation,
);
}
@override
void dispose() {
animController.dispose();
super.dispose();
}
}
class PositionTransition extends AnimatedWidget {
PositionTransition({
@required Animation<double> position,
@required this.flip,
}) : super(listenable: position);
final Animation<double> flip;
@override
Widget build(BuildContext context) {
final position = super.listenable as Animation<double>;
return Positioned(
top: position.value,
child: Transform(
alignment: FractionalOffset.center,
transform: Matrix4.rotationX(math.pi * flip.value),
child: flip.value >= 0.5
? Container(
width: 100,
height: 128,
decoration: BoxDecoration(color: Colors.deepOrange),
)
: Container(
width: 100,
height: 128,
decoration: BoxDecoration(color: Colors.amber),
),
),
);
}
}