Как вызвать setState (перестроить страницу) после всплывающего окна PopUpWindow? - PullRequest
0 голосов
/ 28 октября 2019

Я пытаюсь обновить / перестроить маршрут под всплывающим окном, когда всплывающее окно выскочило, используя Navigator.pop (context). Во всплывающем окне пользователь может добавить что-то в список, а маршрут под (страницей) добавленного элемента отображается в ListView. Поэтому, в частности, мне нужно, чтобы мой ListView был в курсе актуального списка. Но ничего, что я еще не пробовал, сработало.

Как уже упоминалось, я уже пробовал довольно много вещей, в том числе: didPopNext () (с использованием RouteAware), changeExternalState (которую я не совсем понял), пытаясь передать функцию, содержащую только setState (() {}) и другие вещи.

Надеюсь, кто-нибудь может помочь с тем, как я могу перестроить ListView, когда всплывающее окно выскочило.

Заранее спасибо.

Этот пример должен довольно близко подвести итог моей проблемы (не мог показать вам реальный код, потому что он получил более 2000 строк, но основные элементы проблемы должны быть здесь):

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)"),
            ),
          ),
        ]
      ),
    );
  }
}

1 Ответ

0 голосов
/ 28 октября 2019

Вы можете добавить функцию в 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)"),
              ),
            ),
          ]),
    );
  }
}
...