标题.更具体地说,我需要实现一个由FloatingActionButton控制的秒表.然而,即使我静态声明了秒表类,我根本无法访问SetState()成员函数,这使得不可能从外部更新秒表的开始/停止状态.

最小例子:

import 'package:flutter/material.dart';
import 'dart:async';

void main() {
  runApp(
    app(),
  );
}

class StopWatch extends StatefulWidget {
  const StopWatch({super.key});

  @override
  State<StopWatch> createState() => _StopWatchState();
}

class _StopWatchState extends State<StopWatch> {
  static final Stopwatch _stopwatch = Stopwatch();
  late Timer _timer;
  String _result = "0";

  void Start() {
    _timer = Timer.periodic(
      const Duration(milliseconds: 1),
      (Timer t) {
        setState(
          () {
            _result = _stopwatch.elapsed.inSeconds.toString();
          },
        );
      },
    );
    _stopwatch.start();
  }

  void Stop() {
    _timer.cancel();
    _stopwatch.stop();
  }

  @override
  Widget build(BuildContext context) {
    return Text(_result);
  }
}

class app extends StatelessWidget {
  app({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: SingleChildScrollView(
        child: Scaffold(
          body: StopWatch(),
          floatingActionButton: FloatingActionButton.small(
            onPressed: () {},
          ),
        ),
      ),
    );
  }
}

我试过查看事件监听程序,但它们似乎不是适合这项工作的工具.

应用程序的当前状态使得抽象出时钟逻辑变得不可行,只能使用有状态小部件来更新文本.

我也试图寻找一种将FloatingActionButton包含在StopWatch类中的方法,但似乎没有一种方法可以将它放在继承制的最外层,即MaterialApp,更不用说将其放在Scaffold类中了.

推荐答案

setState不应该从小部件本身的外部访问,它是隐藏的state类的一部分.

你可以采取类似于TextField的方法,并有一个控制器,允许你监听和修改你的计时器的内部状态.

class StopWatchController extends ValueNotifier<int> {
  StopWatchController() : super(0);

  /// The underlying [Timer].
  Timer? _timer;

  /// Flag to check a timer is running.
  bool get running => _timer != null;

  void start() {
    value = 0;
    _timer = Timer.periodic(
      const Duration(milliseconds: 1),
      (_) => value = value + 1,
    );
  }

  void stop() {
    value = 0;
    _timer?.cancel();
    _timer = null;
  }

  @override
  void dispose() {
    _timer?.cancel();
    super.dispose();
  }
}

然后,任何小部件都可以对该控制器发出的更改进行listen:

class App extends StatefulWidget {
  const App({super.key});

  @override
  State<App> createState() => _AppState();
}

class _AppState extends State<App> {
  final StopWatchController _controller = StopWatchController();

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Stopwath Demo',
      home: Scaffold(
        body: StopWatch(controller: _controller),
        floatingActionButton: FloatingActionButton.small(
          child: ListenableBuilder(
            listenable: _controller,
            builder: (ctx, _) => Icon(_controller.running ? Icons.stop : Icons.play_arrow),
          ),
          onPressed: () {
            if (_controller.running) {
              _controller.stop();
            } else {
              _controller.start();
            }
          },
        ),
      ),
    );
  }
}

class StopWatch extends StatelessWidget {
  const StopWatch({super.key, required this.controller});

  final StopWatchController controller;

  @override
  Widget build(BuildContext context) {
    return ListenableBuilder(
      listenable: controller,
      builder: (ctx, _) {
        return Center(
          child: Text(controller.value.toString()),
        );
      },
    );
  }
}

Flutter相关问答推荐

Flutter ReorderableListView在可滚动父级中无法完美工作

关闭视频通话,相机仍在运行!(Flutter WebRTC)

文本未设置在集装箱摆动的中心

如何在FiRestore中正确编写OR查询

如何在WidgetRef引用外部的函数中使用Riverpod刷新数据

有没有一种正确的方法可以通过上下滑动在两个小部件(在我的情况下是应用程序栏)之间切换?

如何处理Flutter Riverpod异步通知器中的状态和数据库

修复后期变量的抖动皮棉

Flutter 应用程序中的Firebase实时数据库中的orderByChild()不适用于我

在选项卡栏视图中搜索和筛选不起作用

有没有方法可以从当前时间轻松计算TimeStamp?

如何手动将 FirebaseAuth 用户邮箱验证状态设置为 true

我无法找到修复此错误的位置,指出无法使用静态访问来访问实例成员

在使用 Android 12+ 的真实 Android 设备上,SingleChildScrollView 中最初位于视口之外的无响应 Web 视图

在允许屏幕 Select 和点击的同时保持通用对话框显示

Flutter 错误:OutletListModel类型的值不能分配给List类型的变量?

如何在 flutter 中使用带有有效负载数据的重定向来执行 firebase 推送通知.?

graphql_flutter 错误:非抽象类GraphQLWebSocketChannel缺少实现

Flutter:如何判断嵌套列表是否包含值

如何在 ListView.builder 中扩展文本?