Flutter架构问题/回调函数

时间:2018-10-30 05:30:36

标签: dart flutter

我是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),
    );
  }
}

1 个答案:

答案 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,
  });