flutter 从另一个有状态小部件调用有状态小部件的方法

w8f9ii69  于 2023-06-24  发布在  Flutter
关注(0)|答案(3)|浏览(197)

我是Flutter的新手,最近我遇到了一个挑战。我有以下文件:

  1. main.dart
import 'package:chatgpt_chat/testpage.dart';
import 'package:flutter/material.dart';

void main() => runApp(const TestAPP());

class TestAPP extends StatelessWidget {
  const TestAPP({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: TestScaffold(),
    );
  }
}

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

  @override
  State<TestScaffold> createState() => _TestScaffoldState();
}

class _TestScaffoldState extends State<TestScaffold> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Timer Example'),
      ),
      body: const Center(
        child: TimerWidget(),
      ),
      floatingActionButton: FloatingActionButton(onPressed: (){}),
    );
  }
}
  1. timerWidget.dart:
import 'dart:async';

import 'package:flutter/material.dart';

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

  @override
  State<TimerWidget> createState() => _TimerWidgetState();
}

class _TimerWidgetState extends State<TimerWidget> {
  int _seconds = 0;
  late Timer _timer;

  @override
  void initState() {
    super.initState();
    _startTimer();
  }

  void _startTimer() {
    _timer = Timer.periodic(const Duration(seconds: 1), (timer) {
      setState(() {
        _seconds++;
      });
    });
  }

  void _stopTimer() {
    _timer.cancel();
  }

  void _resetTimer() {
    setState(() {
      _seconds = 0;
    });
  }

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

  @override
  Widget build(BuildContext context) {
    String formattedTime = _formatTime(_seconds);

    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        Text(
          formattedTime,
          style: const TextStyle(fontSize: 24),
        ),
        const SizedBox(height: 16),
        Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton(
              onPressed: _stopTimer,
              child: const Text('Stop'),
            ),
            const SizedBox(width: 16),
            ElevatedButton(
              onPressed: _resetTimer,
              child: const Text('Reset'),
            ),
          ],
        ),
      ],
    );
  }

  String _formatTime(int seconds) {
    int minutes = seconds ~/ 60;
    int remainingSeconds = seconds % 60;
    return '$minutes:${remainingSeconds.toString().padLeft(2, '0')}';
  }
}

你能帮我演示一下如何从FloatingActionButton中的TimerWidget调用startTimer方法吗?我在不同的程序中有一个问题,解决这个特殊的问题会帮助我解决。我真的很感谢你提供你的解决方案。
我找了类似的帖子,但它们并不能完全解决我的问题。我只需要在floatingActionButton中使用startTimer方法

vwkv1x7d

vwkv1x7d1#

您可以创建一个自定义TimerWidgetControllerTimerWidget在构建时需要作为参数,以便将函数_startTime的引用分配给它。
通过这样做,您不需要在TimerWidget中公开任何内容。
这个函数现在可以通过使用TimerWidgetController的示例从其他小部件调用,当然,这个示例传递给了TimeWidget
请检查验证码:

  • timer_widget_controller.dart
class TimerWidgetController {
      late Function? startTimer;
    }
  • timer_widget.dart
import 'dart:async';

import 'package:flutter/material.dart';

import 'timer_widget_controller.dart';

class TimerWidget extends StatefulWidget {
  final TimerWidgetController controller;
  const TimerWidget({
    Key? key,
    required this.controller,
  }) : super(key: key);

  @override
  State<TimerWidget> createState() => _TimerWidgetState();
}

class _TimerWidgetState extends State<TimerWidget> {
  int _seconds = 0;
  late Timer _timer;

  @override
  void initState() {
    super.initState();
    widget.controller.startTimer = _startTimer;
    _startTimer();
  }

  void _startTimer() {
    _timer = Timer.periodic(const Duration(seconds: 1), (timer) {
      setState(() {
        _seconds++;
      });
    });
  }

  void _stopTimer() {
    _timer.cancel();
  }

  void _resetTimer() {
    setState(() {
      _seconds = 0;
    });
  }

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

  @override
  Widget build(BuildContext context) {
    String formattedTime = _formatTime(_seconds);

    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        Text(
          formattedTime,
          style: const TextStyle(fontSize: 24),
        ),
        const SizedBox(height: 16),
        Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton(
              onPressed: _stopTimer,
              child: const Text('Stop'),
            ),
            const SizedBox(width: 16),
            ElevatedButton(
              onPressed: _resetTimer,
              child: const Text('Reset'),
            ),
          ],
        ),
      ],
    );
  }

  String _formatTime(int seconds) {
    int minutes = seconds ~/ 60;
    int remainingSeconds = seconds % 60;
    return '$minutes:${remainingSeconds.toString().padLeft(2, '0')}';
  }
}
  • main.dart
import 'package:flutter/material.dart';

import 'timer_widget_controller.dart';
import 'timer_widget.dart';

void main() => runApp(const TestAPP());

class TestAPP extends StatelessWidget {
  const TestAPP({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: TestScaffold(),
    );
  }
}

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

  @override
  State<TestScaffold> createState() => _TestScaffoldState();
}

class _TestScaffoldState extends State<TestScaffold> {
  late final TimerWidgetController _timerWidgetController;

  @override
  void initState() {
    super.initState();
    _timerWidgetController = TimerWidgetController();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Timer Example'),
      ),
      body: Center(
        child: TimerWidget(
          controller: _timerWidgetController,
        ),
      ),
      floatingActionButton: FloatingActionButton(onPressed: () {
        _timerWidgetController.startTimer?.call();
      }),
    );
  }
}
b1payxdu

b1payxdu2#

_TestScaffoldState更改为

class _TestScaffoldState extends State<TestScaffold> {
  GlobalKey<TimerWidgetState> key = GlobalKey<TimerWidgetState>();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Timer Example'),
      ),
      body: Center(
        child: TimerWidget(key: key),
      ),
      floatingActionButton: FloatingActionButton(onPressed: (){
        key.currentState?.startTimer();
      }),
    );
  }
}

此外,您需要通过删除下划线将startTimerTimerWidgetState公开,以便它们可以被使用。比如说

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

  @override
  State<TimerWidget> createState() => TimerWidgetState();
}

class TimerWidgetState extends State<TimerWidget> {
  int _seconds = 0;
  late Timer _timer;

  @override
  void initState() {
    super.initState();
    startTimer();
  }

  void startTimer() {
  ...
vzgqcmou

vzgqcmou3#

我不知道您为什么要以一种困难的方式运行计时器(调用startTimer方法),但现在我将按照您的要求来做。
由于上面其他人提到了如何使用GlobalKey以及如何创建和求解控制器,因此我将使用更原始的方法。
我将做一个简单的示例代码并展示给你。
-main.dart

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

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

  @override
  State<TestScaffold> createState() => _TestScaffoldState();
}

class _TestScaffoldState extends State<TestScaffold> {
  bool timer = false;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Timer Example'),
      ),
      body: Center(child: TimerWidget(timerBool: timer)),
      floatingActionButton: FloatingActionButton(
        onPressed: _callTimer,
        child: const Icon(Icons.play_arrow_rounded),
      ),
    );
  }

  void _callTimer() {
    setState(() {
      timer = true;
    });
  }
 }

-timerWidget.dart

class TimerWidget extends StatefulWidget {
  bool timerBool;

  TimerWidget({
    Key? key,
    required this.timerBool,
  }) : super(key: key);

  @override
  State<TimerWidget> createState() => _TimerWidgetState();
}

class _TimerWidgetState extends State<TimerWidget> {
  int _seconds = 0;
  Timer _timer = Timer(const Duration(seconds: 1), () {});
  String timerCheck = 'ready';

  @override
  void initState() {
    super.initState();
  }

  void _startTimer() {
    timerCheck = 'startinggg';
    _timer = Timer.periodic(const Duration(seconds: 1), (timer) {
      setState(() {
        _seconds++;
      });
    });
    print('startTimer ${_timer.hashCode}');
  }

  @override
  Widget build(BuildContext context) {
    String formattedTime = _formatTime(_seconds);
    if (widget.timerBool && !_timer.isActive) {
      _startTimer();
    }

    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        Text(
          timerCheck,
          style: Theme.of(context).textTheme.headlineMedium,
        ),
        const SizedBox(height: 20),
        Text(
          formattedTime,
          style: const TextStyle(fontSize: 24),
        ),
        const SizedBox(height: 16),
        Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton(
              onPressed: _stopTimer,
              child: const Text('Stop'),
            ),
            const SizedBox(width: 16),
            ElevatedButton(
              onPressed: _resetTimer,
              child: const Text('Reset'),
            ),
          ],
        ),
      ],
    );
  }

  void _stopTimer() {
    if (!widget.timerBool) return;
    setState(() {
      timerCheck = 'stopppp';
      widget.timerBool = false;
    });
    _timer.cancel();
    print('cancel ${_timer.hashCode}');
  }

  void _resetTimer() {
    setState(() {
      _seconds = 0;
    });
  }

  String _formatTime(int seconds) {
    int minutes = seconds ~/ 60;
    int remainingSeconds = seconds % 60;
    return '$minutes:${remainingSeconds.toString().padLeft(2, '0')}';
  }

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

告诉你,上面回答的两位遗漏了一部分。连续按FloatingActionButton会产生多个计时器,并且只有最后生成的计时器才能被取消()。
因此,您需要在startTimer()中添加一个条件,如下所示。

if( (your timer).isActive ) return;

相关问题