PopUpWindow弹出后如何调用setState(重建页面)?

How to call setState (rebuild page), after pop of PopUpWindow?

我正在尝试 update/rebuild 弹出窗口 window 弹出窗口 window 下的路由,使用 Navigator.pop(上下文)。在弹出窗口 window 上,用户可以向列表中添加内容,在下方(页面)的路由中,添加的项目显示在 ListView 中。所以更具体地说,我需要我的 ListView 与实际列表保持同步。但是我还没有尝试过任何东西,都奏效了。

如前所述,我已经尝试了很多东西,包括: didPopNext()(使用 RouteAware)、changedExternalState(我不太了解)、尝试传递仅包含 setState(() {}) 的函数以及其他内容。

希望有人能帮助我如何在弹出 window 弹出时重建 ListView。

提前致谢。

这个例子应该很好地总结了我的问题(无法向您展示实际的代码,因为它已经超过 2.000 行,但问题的核心要素应该在这里):

import 'package:flutter/material.dart';

void main() => runApp(new MaterialApp(
  home: MyPage()));

class PopupLayout extends ModalRoute<void> {
  @override
  Duration get transitionDuration => Duration(milliseconds: 300);
  @override
  bool get opaque => false;
  @override
  bool get barrierDismissible => false;
  @override
  bool get semanticsDismissible => true;
  @override
  Color get barrierColor =>
      bgColor == null ? Colors.black.withOpacity(0.5) : bgColor;
  @override
  String get barrierLabel => null;
  @override
  bool get maintainState => false;


  double top;
  double bottom;
  double left;
  double right;
  Color bgColor;
  final Widget child;

  PopupLayout(
      {Key key,
      this.bgColor,
      @required this.child,
      this.top,
      this.bottom,
      this.left,
      this.right});

  @override
  Widget buildPage(
    BuildContext context,
    Animation<double> animation,
    Animation<double> secondaryAnimation,
  ) {
    if (top == null) this.top = 10;
    if (bottom == null) this.bottom = 20;
    if (left == null) this.left = 20;
    if (right == null) this.right = 20;

    return GestureDetector(
      onTap: () {},
      child: Material(
        type: MaterialType.transparency,
        child: _buildOverlayContent(context),
      ),
    );
  }
  Widget _buildOverlayContent(BuildContext context) {
    return Container(
      margin: EdgeInsets.only(
          bottom: this.bottom,
          left: this.left,
          right: this.right,
          top: this.top),
      child: child,
    );
  }

  @override
  Widget buildTransitions(BuildContext context, Animation<double> animation,
    Animation<double> secondaryAnimation, Widget child) {
    return FadeTransition(
      opacity: animation,
      child: ScaleTransition(
        scale: animation,
        child: child,
      ),
    );
  }
}

class PopupContent extends StatefulWidget {
  final Widget content;
  PopupContent({
    Key key,
    this.content,
  }) : super(key: key);
  _PopupContentState createState() => _PopupContentState();
}

class _PopupContentState extends State<PopupContent> {
  @override
  void initState() {
    super.initState();
  }
  @override
  Widget build(BuildContext context) {
    return Container(
      child: widget.content,
    );
  }
}

popupContent(BuildContext context, Widget widget,
      {BuildContext popupContext}) {
  Navigator.push(
    context,
    PopupLayout(
      top: 120,
      left: 20,
      right: 20,
      bottom: 120,
      child: PopupContent(
        content: Scaffold(
          backgroundColor: Colors.white,
          resizeToAvoidBottomInset: false,
          body: widget,
        ),
      ),
    ),
  );
}

Widget popupWidget(BuildContext context) {
  return new Container(
    child: Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        Text("This is a popupPage"),
          FlatButton(
          onPressed: () {
            list.add("Irrelevant");
            Navigator.pop(context); //The rebuild of the page underneath, needs to be called when this pops
          },
      child: Text("Press me to change text on home page"),
        ),
      ]
    ),
  );
}

List list = [];

class MyPage extends StatefulWidget {
  @override
  createState() => MyPageState();
}

class MyPageState extends State<MyPage> {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Center(
            child: Container(
              width: 300,
              height: 400,
              child: ListView.builder(
                itemCount: list.length,
                itemBuilder: (BuildContext context, int index) {
                  return Center(
                    child: Text(index.toString()),
                  );
                },
              ),
            ),
          ),
          Center(
            child: FlatButton(
              onPressed: () {
                popupContent(context, popupWidget(context));
              },
              child: Text("Press me for popup window"),
            ),
          ),
          Center(
            child: FlatButton(
              onPressed: () {
                setState(() {});
              },
              child: Text("Press me to rebuild page (setState)"),
            ),
          ),
        ]
      ),
    );
  }
}

您可以在MyPage 中添加一个函数并将其传递给您的popUpWidget。代码:

import 'package:flutter/material.dart';

void main() => runApp(new MaterialApp(home: MyPage()));

class PopupLayout extends ModalRoute<void> {
  @override
  Duration get transitionDuration => Duration(milliseconds: 300);
  @override
  bool get opaque => false;
  @override
  bool get barrierDismissible => false;
  @override
  bool get semanticsDismissible => true;
  @override
  Color get barrierColor =>
      bgColor == null ? Colors.black.withOpacity(0.5) : bgColor;
  @override
  String get barrierLabel => null;
  @override
  bool get maintainState => false;

  double top;
  double bottom;
  double left;
  double right;
  Color bgColor;
  final Widget child;

  PopupLayout(
      {Key key,
      this.bgColor,
      @required this.child,
      this.top,
      this.bottom,
      this.left,
      this.right});

  @override
  Widget buildPage(
    BuildContext context,
    Animation<double> animation,
    Animation<double> secondaryAnimation,
  ) {
    if (top == null) this.top = 10;
    if (bottom == null) this.bottom = 20;
    if (left == null) this.left = 20;
    if (right == null) this.right = 20;

    return GestureDetector(
      onTap: () {},
      child: Material(
        type: MaterialType.transparency,
        child: _buildOverlayContent(context),
      ),
    );
  }

  Widget _buildOverlayContent(BuildContext context) {
    return Container(
      margin: EdgeInsets.only(
          bottom: this.bottom,
          left: this.left,
          right: this.right,
          top: this.top),
      child: child,
    );
  }

  @override
  Widget buildTransitions(BuildContext context, Animation<double> animation,
      Animation<double> secondaryAnimation, Widget child) {
    return FadeTransition(
      opacity: animation,
      child: ScaleTransition(
        scale: animation,
        child: child,
      ),
    );
  }
}

class PopupContent extends StatefulWidget {
  final Widget content;
  PopupContent({
    Key key,
    this.content,
  }) : super(key: key);
  _PopupContentState createState() => _PopupContentState();
}

class _PopupContentState extends State<PopupContent> {
  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      child: widget.content,
    );
  }
}

popupContent(BuildContext context, Widget widget, {BuildContext popupContext}) {
  Navigator.push(
    context,
    PopupLayout(
      top: 120,
      left: 20,
      right: 20,
      bottom: 120,
      child: PopupContent(
        content: Scaffold(
          backgroundColor: Colors.white,
          resizeToAvoidBottomInset: false,
          body: widget,
        ),
      ),
    ),
  );
}

Widget popupWidget(BuildContext context, Function callback) {
  //Pass The Function Here //////////////////////
  return new Container(
    child:
        Column(mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[
      Text("This is a popupPage"),
      FlatButton(
        onPressed: () {
          list.add("Irrelevant");
          callback(); // Call It Here /////////////////////////
          Navigator.pop(
              context); //The rebuild of the page underneath, needs to be called when this pops
        },
        child: Text("Press me to change text on home page"),
      ),
    ]),
  );
}

List list = [];

class MyPage extends StatefulWidget {
  @override
  createState() => MyPageState();
}

class MyPageState extends State<MyPage> {
  //The Calback Function //////////////////////////
  void callback() {
    setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      body: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Center(
              child: Container(
                width: 300,
                height: 400,
                child: ListView.builder(
                  itemCount: list.length,
                  itemBuilder: (BuildContext context, int index) {
                    return Center(
                      child: Text(index.toString()),
                    );
                  },
                ),
              ),
            ),
            Center(
              child: FlatButton(
                onPressed: () {
                  popupContent(context, popupWidget(context, this.callback)); //Passing the Function here ////////////
                },
                child: Text("Press me for popup window"),
              ),
            ),
            Center(
              child: FlatButton(
                onPressed: () {
                  setState(() {});
                },
                child: Text("Press me to rebuild page (setState)"),
              ),
            ),
          ]),
    );
  }
}