Flutter + Riverpod:在有状态小部件中调用函数?

问题描述

我正在构建一个应该通过按下按钮来触发的计时器。计时器是通过有状态小部件中的自动收报机完成的,整个设置非常简单。但是,我的问题是小部件树中用于启动计时器的按钮与计时器本身相距很远,我不知道如何触发从该按钮启动计时器的方法

我知道我可以将函数作为参数传递,但这对这个项目来说并不实用。理想情况下,我想使用 Riverpod 连接小部件,可以吗? (对不起,如果这是一个愚蠢的问题,我对 Flutter 和 Riverpod 还很陌生)。

我的计时器代码

class SimpleTimer extends StatefulWidget {
  const SimpleTimer({Key? key}) : super(key: key);

  @override
  _SimpleTimerState createState() => _SimpleTimerState();
}

class _SimpleTimerState extends State<SimpleTimer>
    with TickerProviderStateMixin {
  late Ticker _ticker;
  Duration elapsedtime = Duration.zero;

  @override
  void initState() {
    super.initState();
    _ticker = this.createTicker(
      (elapsed) => setState(() => elapsedtime = elapsed),);
  }

  @override
  void dispose() {
    super.dispose();
    _ticker.dispose();
  }

  void startTimer() => _ticker.start();

  @override
  Widget build(BuildContext context) {
    return Text(elapsedtime.inSeconds.toString());
  }
}

和按钮的代码

class TimerStartButton extends StatelessWidget {
  const TimerStartButton({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      onpressed: () {},// how to call startTimer from SimpleTimer here? 
      child: Text('start timer'),);
  }
}

解决方法

啊,在 xion 在评论中发布的教程的帮助下弄清楚了。如果有人正在寻找解决方案,我接近它的方法是使用 StateProvider 返回 true 或 false(如果股票行情是否处于活动状态),然后在计时器小部件内部我使用 ProviderListener 来运行一个函数,如果那个计时器改变了。

定时器的新代码:

class SimpleTimer extends StatefulWidget {
  const SimpleTimer({Key? key}) : super(key: key);

  @override
  _SimpleTimerState createState() => _SimpleTimerState();
}

class _SimpleTimerState extends State<SimpleTimer>
    with TickerProviderStateMixin {
  late Ticker _ticker;
  Duration elapsedTime = Duration.zero;

  @override
  void initState() {
    super.initState();
    _ticker = this.createTicker((elapsed) {
      setState(() {
        elapsedTime = elapsed;
      });
    });
  }

  @override
  void dispose() {
    super.dispose();
    _ticker.dispose();
  }

  void startTicker() => _ticker.start();

  @override
  Widget build(BuildContext context) {
    return Consumer(
      builder: (
        BuildContext context,ScopedReader watch,Widget? child,) {
        return ProviderListener(
          onChange: (context,state) => startTicker(),provider: timerProvider,child: Text(
            elapsedTime.inSeconds.toString(),),);
      },);
  }
}

启动按钮的新代码:

class TimerStartButton extends ConsumerWidget {
  const TimerStartButton({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context,ScopedReader watch) {
    return ElevatedButton(
      onPressed: () => context.read(timerProvider).state = true,child: Text('start'),);
  }
}

现在还添加了一个 riverpod StateProvder:

final timerProvider = StateProvider<bool>((ref) {
  return false;
});