英文:
Calling a stateful widget's method from another stateful widget
问题
I can help you with the translation. Here is the relevant part of your text:
"我是Flutter新手,最近遇到了一个挑战。我有以下文件:
- 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: (){},
),
);
}
}
- 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')}';
}
}
Could you please help me out by showing how I can call the startTimer method from TimerWidget in FloatingActionButton? I have a problem in a different program, and solving this particular problem will help me out. I really appreciate it if you provide your solutions.
I looked for similar posts; however, they do not fully solve my problem. I just have to use the startTimer method in the FloatingActionButton."
英文:
I'm new in Flutter, and recently I have encountered with a challange. I have the following files:
- 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: (){}),
);
}
}
- 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')}';
}
}
Could you please help me out by showing how I can call startTimer method from TimerWidget in FloatingActionButton? I have a problem in different program, and solving this particular problem will help me out. I really appreciate it if you provide your solutions.
I looked for similar posts, however they do not fully solve my problem. I just have to use startTimer method in floatingActionButton
答案1
得分: 2
以下是您要翻译的代码部分:
您可以创建一个自定义的 `TimerWidgetController`,并将其作为参数传递给 `TimerWidget`,以便在构建时将函数 `_startTime` 的引用分配给它。
通过这样做,您无需将任何内容公开在 `TimerWidget` 中。
现在,可以通过使用 `TimerWidgetController` 的实例来从其他小部件调用该函数,当然要使用与 `TimeWidget` 相同的实例。
请检查代码:
- timer_widget_controller.dart
```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();
}),
);
}
}
希望这有助于您理解代码的内容。
英文:
You could create a custom TimerWidgetController
that TimerWidget
requires as parameter, when built, in order to assign the reference of the function _startTime
to it.
By doing this, you don't need to make anything public in the TimerWidget
.
The function can now be called from other widgets just by using an instance of TimerWidgetController
, the same one passed to TimeWidget
of course.
Please check the code:
- 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();
}),
);
}
}
答案2
得分: 1
将您的 _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();
}),
);
}
}
此外,您需要将 startTimer
和 TimerWidgetState
更改为公开,去掉下划线以便可以使用。如下所示:
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() {
...
英文:
Change your _TestScaffoldState
to
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();
}),
);
}
}
Furthermore you need to make startTimer
and TimerWidgetState
public by removing the underscore so they can be used. So like:
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() {
...
答案3
得分: 0
我不知道为什么你要以这种困难的方式运行计时器(调用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.headline6,
),
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 (_timer.isActive) return;
这个条件可以确保只有在当前计时器不活动时才启动新的计时器。
英文:
I don't know why you're trying to run the timer(call startTimer method) in a difficult way, but I'll do what you want for now.
Since other people mentioned above how to use GlobalKey and how to create and solve a controller, I'll make it a more primitive way.
I'll make a simple example code and show it to you.
-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();
}
}
For your information, there is a part that the two of you who answered above missed.
Pressing FloatingActionButton continuously results in multiple timers,
and only the last generated one can be canceled().
Therefore, you need to put one condition in startTimer() as below.
if( (your timer).isActive ) return;
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论