我是Flutter的新手,我对构建以下代码有疑问。这是一项正在进行中的工作,但应该说明我的问题。基本上,我有一个带有开始按钮的倒数计时器列表(TimerEntry)。但是,我想摆脱计时器对象内部的按钮逻辑,并将其移至计时器列表(TimerList),以便执行诸如在计时器1完成后启动计时器2或在新计时器停止时停止所有其他计时器的操作计时器启动等。 就像我说的那样,我对Flutter完全陌生,希望有人可以指出我的操作方向。我正在猜测某种自定义回调函数?
import 'package:flutter/material.dart';
class TimedItem extends AnimatedWidget {
TimedItem({this.task, this.timeRemainingInSeconds})
: super(listenable: timeRemainingInSeconds);
final Animation<int> timeRemainingInSeconds;
final String task;
Widget build(BuildContext context) {
String minutes =
'${(timeRemainingInSeconds.value / 60).floor()}'.padLeft(2, '0');
String seconds = '${(timeRemainingInSeconds.value % 60)}'.padLeft(2, '0');
return ListTile(
title: Text(
'$minutes:$seconds',
style: Theme.of(context).textTheme.display2,
),
subtitle: Text(task),
);
}
}
class TimerEntry extends StatefulWidget {
final int index;
final String task;
final Duration duration;
bool currentlyActive;
TimerEntry({this.index, this.task, this.duration, this.currentlyActive});
TimerEntryState createState() => TimerEntryState();
}
class TimerEntryState extends State<TimerEntry> with TickerProviderStateMixin {
AnimationController _controller;
AnimationController get controller {
return _controller;
}
@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: widget.duration,
);
}
@override
Widget build(BuildContext context) {
return Row(
children: <Widget>[
Flexible(
child: TimedItem(
task: widget.task,
timeRemainingInSeconds: IntTween(
begin: controller.duration.inSeconds,
end: widget.currentlyActive ? 0 : widget.duration.inSeconds,
).animate(controller)
),
),
toggleButton()
],
);
}
Widget toggleButton() {
return FloatingActionButton(
onPressed: () {
controller.forward(from: 0.0);
widget.currentlyActive = true;
},
child: widget.currentlyActive
? Icon(Icons.pause_circle_outline)
: Icon(Icons.play_circle_outline),
);
}
}
class TimerList extends StatefulWidget {
final int currentActiveTimer = 0;
/// TODO: get them from outside
final entries = <TimerEntry>[
TimerEntry(
index: 0,
task: "The first task",
duration: Duration(minutes: 3),
currentlyActive: true,
),
TimerEntry(
index: 1,
task: "Another task altogether",
duration: Duration(minutes: 1),
currentlyActive: false,
)
];
@override
_TimerListState createState() => _TimerListState();
}
class _TimerListState extends State<TimerList> {
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: widget.entries.length,
shrinkWrap: true,
itemBuilder: (context, index) {
return TimerEntry(
task: widget.entries[index].task,
duration: widget.entries[index].duration,
currentlyActive: widget.entries[index].currentlyActive,
);
});
}
}
编辑: 这是一个与自定义回调GetTaskButton一起使用的新版本,但是现在我已经无法访问我的动画控制器(请参阅底部的toggleButton函数)。有没有一种方法可以不用将控制器移到列表类?
import 'package:flutter/material.dart';
typedef Widget GetTaskButton(TimerEntry t);
class TimedItem extends AnimatedWidget {
TimedItem({this.task, this.timeRemainingInSeconds})
: super(listenable: timeRemainingInSeconds);
final Animation<int> timeRemainingInSeconds;
final String task;
Widget build(BuildContext context) {
String minutes =
'${(timeRemainingInSeconds.value / 60).floor()}'.padLeft(2, '0');
String seconds = '${(timeRemainingInSeconds.value % 60)}'.padLeft(2, '0');
return ListTile(
title: Text(
'$minutes:$seconds',
style: Theme.of(context).textTheme.display2,
),
subtitle: Text(task),
);
}
}
class TimerEntry extends StatefulWidget {
final int index;
final String task;
final Duration duration;
final GetTaskButton getButton;
bool currentlyActive;
TimerEntry({this.index, this.task, this.duration, this.currentlyActive, this.getButton});
TimerEntryState createState() => TimerEntryState();
}
class TimerEntryState extends State<TimerEntry> with TickerProviderStateMixin {
AnimationController _controller;
AnimationController get controller {
return _controller;
}
@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: widget.duration,
);
}
@override
Widget build(BuildContext context) {
// return Text("test");
return Row(
children: <Widget>[
Flexible(
child: TimedItem(
task: widget.task,
timeRemainingInSeconds: IntTween(
begin: controller.duration.inSeconds,
end: widget.currentlyActive ? 0 : widget.duration.inSeconds,
).animate(controller)
),
),
widget.getButton(widget)
],
);
}
}
class TimerList extends StatefulWidget {
final int currentActiveTimer = 0;
/// TODO: get them from outside
final entries = <TimerEntry>[
TimerEntry(
index: 0,
task: "The first task",
duration: Duration(minutes: 3),
currentlyActive: true,
),
TimerEntry(
index: 1,
task: "Another task altogether",
duration: Duration(minutes: 1),
currentlyActive: false,
)
];
@override
_TimerListState createState() => _TimerListState();
}
class _TimerListState extends State<TimerList> {
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: widget.entries.length,
shrinkWrap: true,
itemBuilder: (context, index) {
return TimerEntry(
task: widget.entries[index].task,
duration: widget.entries[index].duration,
currentlyActive: widget.entries[index].currentlyActive,
getButton: (Widget tButton) => toggleButton(widget.entries[index]),
);
});
}
Widget toggleButton(TimerEntry t) {
return FloatingActionButton(
onPressed: () {
setState(() {
/// TODO: how to access this one?
// t.controller.forward(from: 0.0);
t.currentlyActive = !t.currentlyActive;
});
},
child: t.currentlyActive
? Icon(Icons.pause_circle_outline)
: Icon(Icons.play_circle_outline),
);
}
}
答案 0 :(得分:1)
以下是您可以做的几件事:
创建一个全局列表变量。
List<TimerEntry> myEntries = List<TimerEntry>();
一个将值添加到myEntries列表中的函数。我已经硬编码了可以传递参数以使其动态的值。
void _addTimers() {
myEntries.add(TimerEntry(
index: 0,
task: "The first task",
duration: Duration(minutes: 3),
currentlyActive: true,
));
myEntries.add(TimerEntry(
index: 1,
task: "The Second task",
duration: Duration(minutes: 3),
currentlyActive: true,
));
}
只要需要添加计时器_addTimers();
在TimerList类中-您需要定义一个构造函数以获取列表。
class TimerList extends StatefulWidget {
final int currentActiveTimer = 0;
final List<TimerEntry> entries;
TimerList({this.entries});
&最后,您需要将全局列表变量传递给您对其进行初始化的类。
body: TimerList(entries: myEntries,),
更新: 编辑了toggleButton()以确保其正确响应onTap()。
Widget toggleButton() {
return FloatingActionButton(
onPressed: () {
setState(() {
controller.forward(from: 0.0);
widget.currentlyActive = !widget.currentlyActive;
});
},
child: widget.currentlyActive
? Icon(Icons.pause_circle_outline)
: Icon(Icons.play_circle_outline),
);
}
更新:将AnimationController传递给计时器
class _TimerListState extends State<TimerList> with TickerProviderStateMixin {
List<AnimationController> myAnimationControllers =
List<AnimationController>();
@override
void initState() {
_getControllerList();
super.initState();
}
void _getControllerList() {
widget.entries.forEach((f) {
myAnimationControllers
.add(AnimationController(vsync: this, duration: f.duration));
});
}
然后在构建中将其传递给TimerEntry:
TimerEntry(
task: widget.entries[index].task,
duration: widget.entries[index].duration,
currentlyActive: widget.entries[index].currentlyActive,
controller: myAnimationControllers[index]),
)
class TimerEntry extends StatefulWidget {
final int index;
final String task;
final Duration duration;
bool currentlyActive;
AnimationController controller;
TimerEntry({
this.index,
this.task,
this.duration,
this.currentlyActive,
this.controller,
});