flutter 我的小部件中的变量没有改变

deyfvvtc  于 2023-08-07  发布在  Flutter
关注(0)|答案(2)|浏览(136)

我是一个初学者在Flutter和我试图使新的项目乐趣:象棋钟。一旦其中一个按钮被按下,它应该开始运行,但它没有。请看一下,告诉我哪里做错了。试着指出它,而不是编码它,因为我不想只是复制和粘贴,而是把事情弄清楚。我猜一定是和变量作用域有关的东西。。下面是主.dart文件:

import 'package:flutter/material.dart';
import 'Clock.dart';
void main() {
  runApp(MyApp());
}

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

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        home: Scaffold(
            body: SafeArea(
                child: Column(
              crossAxisAlignment: CrossAxisAlignment.stretch,
      children: <Widget>[
        Expanded(
          child: Chessclock(),
        ),
        Expanded(
          child: Chessclock(),
        )
      ]
    )))
    );
  }
}

字符串
下面是Clock.dart文件:

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

class Chessclock extends StatefulWidget {
   final tim;
   Chessclock({Key? key,required this.tim}): super({});
   var minutes  = this.tim~/60;
   var seconds = this.tim % 60;
   var inGame = false;
   var dur = const Duration(seconds: 1);
   void runtime(t,b){

     if(b){
       sleep(dur);
       _tim--;
     }else{
       return;
     }
   }
   bool inswitch(inGam){
     return !inGam;
   }

  @override
  State<Chessclock> createState() => new _ChessclockState();
}

class _ChessclockState extends State<Chessclock>{

  @override
  // TODO: implement runtimeType
  Widget build(BuildContext context) {
   runtime(tim,inGame);
    return TextButton(
      child: Text('$minutes:$seconds',
      style: TextStyle(fontSize: 30)
      ),
      onPressed: () {
        setState(() {
          inGame = inswitch(inGame);
        });
    },
      style: TextButton.styleFrom(
          foregroundColor: Colors.white,
          backgroundColor: (inGame? Colors.green : Colors.grey),

      )

    );
  }
}


我知道你会很好,因为Dart程序员都是很棒的人。:D个

dtcbnfnu

dtcbnfnu1#

所有这些东西都应该在_ChessclockState中:

var minutes  = widget.tim~/60;
   var seconds = widget.tim % 60;
   var inGame = false;
   var dur = const Duration(seconds: 1);
   void runtime(t,b){

     if(b){
       sleep(dur);
       _tim--;
     }else{
       return;
     }
   }
   bool inswitch(inGam){
     return !inGam;
   }

字符串
此外,您可能需要使用状态生命周期方法,该方法将在第一次和创建小部件后触发一次:

@override
  void initState() {
    super.initState();
    ..do initialization here..
  }


你应该在state lyfecycle上深入研究https://flutterbyexample.com/lesson/stateful-widget-lifecycle#3-initstate

cld4siwp

cld4siwp2#

首先,将tim声明为final是不合理的,因为您需要在您的案例中更新它的值。
如果我没有误解你的意思,那么你实际上是想设置一个计时器(在你的情况下是ChessClock,它可以在触发时倒计时)
对于倒计时逻辑,我们可以直接使用Dart中的Timer.periodic类来代替sleep(),同时注意sleep()dart doc
请小心使用,因为当隔离在睡眠调用中被阻塞时,无法在隔离中处理任何异步操作。
此外,在您的代码中,您希望调用state类中的runtime()方法,在我看来,如果您真的希望从状态访问小部件类的属性,则这将不起作用,IDE应该报告错误(在您的示例中,访问状态类_ChessclockState中的Chessclock中的runtime(),您应该使用关键字widget,例如您的状态类中的widget.runtime()
另外,在代码的这一部分中

onPressed: () {
        setState(() {
          inGame = inswitch(inGame);
        });
    },

字符串
您使用setState调用inswitch()方法,该方法应处理倒数计时逻辑并每秒在ChessClock中减少tim,正如我上面提到的,代码中的倒数计时逻辑可能会因为使用sleep()而导致一些问题
让我们假设您已经修改了代码以使用Timer,并且倒计时逻辑工作良好,但是UI仍然不会像预期的那样每秒都改变。这是因为当在onPressed回调中按下按钮时,您只调用了setState()一次,但时间实际上是不断变化的。
对于这个问题,有一个解决方案,您将倒计时逻辑移动到状态类中,然后您可以执行以下操作:

class _ClockExampleState extends State<ClockExample> {
  Timer? countingTimer = null;
  void triggerCounting() {
    if (countingTimer == null) {
      countingTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
        setState(() {
          if (widget.tim > 0) {
            --widget.tim;
          }
        });
      });
    } else {
      countingTimer!.cancel();
    }
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        /// ...
        /// Button
        ElevatedButton(
            onPressed: () {
              triggerCounting();
            },
            child: Text('Trigger'))
      ],
    );
  }
}


由于您可以在state类中访问setState(),现在您可以创建一个名为triggerCounting的方法,每当widget.tim更新时,该方法都会调用setState(),此时UI应该每秒更新一次
这里是完整的代码(注意,我的代码完全是一个新的应用程序,它创建了一个例子)

主省道

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

void main() {
  runApp(const MyApp());
}

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

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(),
    );
  }
}

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

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return ClockExample();
  }
}

**时钟. dart **

import 'dart:async';
import 'dart:io';

import 'package:flutter/material.dart';

class ClockExample extends StatefulWidget {
  ClockExample({super.key, this.tim = 300});

  int tim;

  int get min {
    return tim ~/ 60;
  }

  int get sec {
    return tim % 60;
  }

  @override
  State<ClockExample> createState() => _ClockExampleState();
}

class _ClockExampleState extends State<ClockExample> {
  Timer? countingTimer = null;
  void triggerCounting() {
    if (countingTimer == null) {
      countingTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
        setState(() {
          print('tim: ${widget.tim}');
          if (widget.tim > 0) {
            --widget.tim;
          }
        });
      });
    } else {
      countingTimer!.cancel();
    }
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        Center(
          child: Text('${widget.min} : ${widget.sec}'),
        ),
        Center(
          child: Text('${widget.tim}'),
        ),
        ElevatedButton(
            onPressed: () {
              triggerCounting();
            },
            child: Text('Trigger'))
      ],
    );
  }
}


我现在也在学习Flutter,可能我的解决方案不是最好的,实际上我的解决方案还存在一些问题,比如父部件无法直接访问计时器的值,注意不仅ClockExample需要访问并显示tim的信息,应用的其他部分可能也需要知道倒计时的值,例如,应用程序可能需要停止游戏并显示对话框时,时间用完了,所以你可能需要考虑将状态拉到所有需要访问状态的小部件之上的小部件,或者你可以考虑使用一些状态管理包,如providerProvider on pub.dev

相关问题