根据延迟在两个小部件之间切换

Switch between two widgets depending on a delay

我有一个状态变量a。如果变量 a100.0,我想显示小部件 A。如果变量 a 不同,那么我想显示小部件 B.

这很简单,看起来像这样:

      child: aOrB(a),  // somewhere in the top-level Scaffold

...

Widget aOrB(double a) {
  if (a == 100.0) {
    return A;
  } else {
    return B;
  }
}

但问题是:如果变量 a 更改为 100.0,我想先显示小部件 B,然后在延迟一段时间后切换到小部件 A .

还有一个问题:如果用户点击小部件 A,我想显示小部件 B 一段时间,然后在延迟一段时间后再次显示小部件 A

条件加起来就是table:

|---------------------|------------------|
|      a == 100.0     |         A        |
|---------------------|------------------|
|      a != 100.0     |         B        |
|---------------------|------------------|
| a == 100.0; t < 5 s |         B        |
|  A.onTap; t < 5 s   |                  |
|---------------------|------------------|

我已经尝试过 Future.delayed、计时器和可见性小部件,但没有成功。

这是我理解的例子! 它适用于 a == 100、a != 00 和时间延迟。 根据您的要求修改它!

double a = 100;

  Widget focusedWidget;

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

    //if you want to predefine a initial widget call the initWidget method !
    //or call the changeWidget for instant output

    changeWidget(a);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: const Text('Let\'s parse some JSON'),
        ),
        body: Container(
          padding: EdgeInsets.fromLTRB(5, 10, 5, 10),
          child: focusedWidget,
        ));
  }

  void initWidget(flag) {
    if (flag == 100) {
      setState(() {
        focusedWidget = Card(
          color: Colors.green,
          child: ListTile(
              onTap: () {
                changeWidget(50);
                //or some value
              },
              title: Text('Widget A',
                  style: TextStyle(
                      color: Colors.black, fontWeight: FontWeight.bold),
                  textAlign: TextAlign.center)),
        );
      });
    } else {
      setState(() {
        focusedWidget = Card(
          color: Colors.red,
          child: ListTile(
              onTap: () {
                changeWidget(100);
              },
              title: Text('Widget B',
                  style: TextStyle(
                      color: Colors.black, fontWeight: FontWeight.bold),
                  textAlign: TextAlign.center)),
        );
      });
    }
  }

  void changeWidget(flag) {
    if (flag == 100) {
      setState(() {
        focusedWidget = Card(
          color: Colors.red,
          child: ListTile(
            onTap: () {
              changeWidget(100);
              //or some value
            },
            title: Text('Widget B',
                style:
                    TextStyle(color: Colors.black, fontWeight: FontWeight.bold),
                textAlign: TextAlign.center),
          ),
        );
      });
      Future.delayed(Duration(seconds: 5), () {
        setState(() {
          focusedWidget = Card(
            color: Colors.green,
            child: ListTile(
              onTap: () {
                changeWidget(50);
              },
              title: Text('Widget A',
                  style: TextStyle(
                      color: Colors.black, fontWeight: FontWeight.bold),
                  textAlign: TextAlign.center),
            ),
          );
        });
      });
    } else {
      setState(() {
        focusedWidget = Card(
          color: Colors.red,
          child: ListTile(
            onTap: () {
              changeWidget(100);
            },
            title: Text('Widget B',
                style:
                    TextStyle(color: Colors.black, fontWeight: FontWeight.bold),
                textAlign: TextAlign.center),
          ),
        );
      });
    }
  }

最后,以下对我有用。 Future.delayed 很好,但是当 Future 连续调用几次时,它不能被取消。这样,用户可以在几秒钟内 运行 多个 5 秒延迟的 Futures(通过 onTap,或通过更改 a 的值,或通过 运行ning setState 过于频繁)。这使得 onTap 完全无法使用,因为 运行ning Futures 击败了 onTaps 并隐藏了小部件 B 而不管用户的操作如何。这使得@Naveen Avidi 的回答在现实中不太有用。

所以你需要一个计时器来做到这一点。你需要 运行 它在后台异步。我发现,唯一可以在后台 运行 计时器的地方是 build() 方法中的 return 之前。每次重绘app时都会调用这里的代码,所以你可以检查一下,如果a真的改变了,如果你真的想要运行一个Timer,取消之前的Timer并运行一个新的一.

监听 a 中 setState 变化的最简单方法是复制 a 的值并在每次重绘应用程序时进行比较。代码中完全相同的地方。

double previousA;
bool showB;
Timer bTimer;

...

@override
Widget build(BuildContext context) {
  if (previousA != a) {
    if (a == 100.0) {
      showB = true;
      bTimer?.cancel();
      bTimer = Timer(Duration(seconds: 5), () {
        setState(() => showB = false);
      });
    } else {
      showB = true;
    }
    previousA = a;
  }
  return Scaffold(

...

        child: aOrB(showB),

...

aOrB(showB){
  if (showB == true) {

  } else {

  }
}

如果您还想在代码中的某处设置 showB,无论 a 是否更改,您也可以复制 showB 并监听其更改:

if (previousShowB != showB) {
  if (showB == true) {
    bTimer?.cancel();
    bTimer = Timer(Duration(seconds: 5), () {
      setState(() => showB = false);
    });
  }
}

...

setState(() => showB = true);