【发布时间】:2020-12-17 03:29:21
【问题描述】:
几天以来,我一直在尝试将带有倒数计时器的动画有状态子小部件连接到具有用户交互的父有状态小部件。我在 Andrey 的一个类似问题上找到了这个answer(使用我没有使用的 Tween),这已经有很大帮助,但我仍然无法让它发挥作用。我的假设是,孩子的 initState 可能是原因。定时器的代码来自here。
我已经删除了相当多的代码,包括一些引用的函数/类。这应该提供更清晰的逻辑图片:
- 在 MainPageState 中我声明并初始化动画的 _controller
- 在 MainPageState 中,我将托管的无状态小部件 CreateKeypad 称为“开始”键
- 点击go时,该事件返回MainPageState并执行
_controller.reverse(from: 1.0); - 在 MainPageState 中,我调用有状态小部件 CountDownTimer 来呈现计时器
- 在 _CountDownTimerState 我不确定我的 initState 是否正确
- 在 _CountDownTimerState 中,我使用来自 timer code source 的 CustomTimerPainter 构建动画
动画应在顶部渲染一个白色甜甜圈和一个红色递减弧。但是,我只看到白色甜甜圈,而不是红色计时器的弧线。任何提示都非常感谢。
class MainPage extends StatefulWidget {
MainPage({Key key, this.title}) : super(key: key);
final String title;
@override
_MainPageState createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> with TickerProviderStateMixin {
AnimationController _controller;
var answer="0", correctAnswer = true, result = 0;
@override
void initState() {
super.initState();
_controller = AnimationController(vsync: this, duration: Duration(seconds: 7));
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
),
child: SafeArea(
child: Container(
child: Column(
children: <Widget>[
CreateKeypad( // creates a keypad with a go button. when go is clicked, countdown shall start
prevInput: int.parse((answer != null ? answer : "0")),
updtedInput: (int val) {
setState(() => answer = val.toString());
},
goSelected: () {
setState(() {
if (answer == result.toString()) {
correctAnswer = true;
}
final problem = createProblem();
result = problem.result;
});
_controller.reverse(from: 1.0); // start the countdown animation
Future.delayed(const Duration(milliseconds: 300,),
() => setState(() => correctAnswer = true));
},
),
CountDownTimer(_controller), // show countdown timer
]
),
),
)
);
}
}
// CREATE KEYPAD - all keys but "1! and "go" removed
class CreateKeypad extends StatelessWidget {
final int prevInput;
final VoidCallback goSelected;
final Function(int) updtedInput;
CreateKeypad({@required this.prevInput, @required this.updtedInput, this.goSelected});
@override
Widget build(BuildContext context) {
return Row(
children: <Widget> [
Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(2.0),
child: SizedBox(
width: 80.0, height: 80.0,
child: CupertinoButton(
child: Text("1", style: TextStyle(color: CupertinoColors.black)),
onPressed: () {
updtedInput(1);
},
),
),
),
Padding(
padding: const EdgeInsets.all(2.0),
child: SizedBox(
width: 80.0, height: 80.0,
child: CupertinoButton(
child: Text("Go!", style: TextStyle(color: CupertinoColors.black)),
onPressed: () => goSelected(),
),
),
),
],
),
]
);
}
}
// CREATE COUNTDOWN https://medium.com/flutterdevs/creating-a-countdown-timer-using-animation-in-flutter-2d56d4f3f5f1
class CountDownTimer extends StatefulWidget {
CountDownTimer(this._controller);
final AnimationController _controller;
@override
_CountDownTimerState createState() => _CountDownTimerState();
}
class _CountDownTimerState extends State<CountDownTimer> with TickerProviderStateMixin {
@override
void initState() {
super.initState(); // here I have some difference to Andrey's answer because I do not use Tween
}
String get timerString {
Duration duration = widget._controller.duration * widget._controller.value;
return '${duration.inMinutes}:${(duration.inSeconds % 60)
.toString()
.padLeft(2, '0')}';
}
@override
Widget build(BuildContext context) {
return Container(
child: AnimatedBuilder(
animation: widget._controller,
builder:
(BuildContext context, Widget child) {
return CustomPaint(
painter: CustomTimerPainter( // this draws a white donut and a red diminishing arc on top
animation: widget._controller,
backgroundColor: Colors.white,
color: Colors.red,
));
},
),
);
}
}
【问题讨论】:
标签: flutter dart state parent-child