web-dev-qa-db-de.com

Flatter-Navigator zwingen, den Status beim Poppen neu zu laden

Ich habe eine StatefulWidget in Flutter with button, die mich mit Navigator.Push() zu einer anderen StatefulWidget navigiert. Beim zweiten Widget ändere ich den globalen Status (einige Benutzereinstellungen). Wenn ich vom zweiten Widget zum ersten zurückkomme, ist das erste Widget mit Navigator.pop() im alten Zustand, aber ich möchte, dass es neu geladen wird. Irgendeine Idee, wie das geht? Ich habe eine Idee, aber sie sieht hässlich aus:

  1. pop zum Entfernen des zweiten Widgets (aktuelles)
  2. pop wieder, um das erste Widget zu entfernen (vorheriges)
  3. Erstes Widget drücken (es sollte ein Neuzeichnen erzwingen)
8
bartektartanus

Es gibt ein paar Dinge, die Sie hier tun können. @ Mahis Antwort könnte korrekt sein, wenn sie etwas genauer ist und tatsächlich Push anstelle von showDialog verwendet, da das OP danach gefragt hat. Dies ist ein Beispiel, das Navigator.Push verwendet:

import 'package:flutter/material.Dart';

class SecondPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Container(
      color: Colors.green,
      child: new Column(
        children: <Widget>[
          new RaisedButton(
            onPressed: () => Navigator.pop(context),
            child: new Text("back"),
          ),
        ],
      ),
    );
  }
}

class FirstPage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => new FirstPageState();
}

class FirstPageState extends State<FirstPage> {

  Color color = Colors.white;

  @override
  Widget build(BuildContext context) {
    return new Container(
      color: color,
      child: new Column(
        children: <Widget>[
          new RaisedButton(
              child: new Text("next"),
              onPressed: () {
                Navigator
                    .Push(
                  context,
                  new MaterialPageRoute(builder: (context) => new SecondPage()),
                )
                    .then((value) {
                  setState(() {
                    color = color == Colors.white ? Colors.grey : Colors.white;
                  });
                });
              }),
        ],
      ),
    );
  }
}

void main() => runApp(
      new MaterialApp(
        builder: (context, child) => new SafeArea(child: child),
        home: new FirstPage(),
      ),
    );

Es gibt jedoch eine andere Möglichkeit, dies in Ihren Anwendungsfall zu integrieren. Wenn Sie global als etwas verwenden, das sich auf den Aufbau Ihrer ersten Seite auswirkt, können Sie ein InheritedWidget verwenden, um Ihre globalen Benutzereinstellungen zu definieren. Bei jeder Änderung wird FirstPage neu erstellt. Dies funktioniert sogar in einem Stateless-Widget (siehe unten) (sollte jedoch auch in einem Stateful-Widget funktionieren).

Ein Beispiel für das Flattern von "Geerbt" ist das Theme der App, obwohl es in einem Widget definiert wird, anstatt es direkt so zu erstellen, wie ich es hier habe.

import 'package:flutter/material.Dart';
import 'package:meta/meta.Dart';

class SecondPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Container(
      color: Colors.green,
      child: new Column(
        children: <Widget>[
          new RaisedButton(
            onPressed: () {
              ColorDefinition.of(context).toggleColor();
              Navigator.pop(context);
            },
            child: new Text("back"),
          ),
        ],
      ),
    );
  }
}

class ColorDefinition extends InheritedWidget {
  ColorDefinition({
    Key key,
    @required Widget child,
  }): super(key: key, child: child);

  Color color = Colors.white;

  static ColorDefinition of(BuildContext context) {
    return context.inheritFromWidgetOfExactType(ColorDefinition);
  }

  void toggleColor() {
    color = color == Colors.white ? Colors.grey : Colors.white;
    print("color set to $color");
  }

  @override
  bool updateShouldNotify(ColorDefinition oldWidget) =>
      color != oldWidget.color;
}

class FirstPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    var color = ColorDefinition.of(context).color;

    return new Container(
      color: color,
      child: new Column(
        children: <Widget>[
          new RaisedButton(
              child: new Text("next"),
              onPressed: () {
                Navigator.Push(
                  context,
                  new MaterialPageRoute(builder: (context) => new SecondPage()),
                );
              }),
        ],
      ),
    );
  }
}

void main() => runApp(
      new MaterialApp(
        builder: (context, child) => new SafeArea(
              child: new ColorDefinition(child: child),
            ),
        home: new FirstPage(),
      ),
    );

Wenn Sie ein geerbtes Widget verwenden, müssen Sie sich keine Sorgen machen, dass Sie nach dem Popup der von Ihnen geposteten Seite suchen müssen. Dies funktioniert für grundlegende Anwendungsfälle, kann jedoch in einem komplexeren Szenario zu Problemen führen.

7
rmtmckenzie

Es gibt zwei Dinge, von denen Daten übertragen werden

  • 1. Seite bis 2. Seite

    Verwenden Sie dies auf der ersten Seite

    // sending "Foo" from 1st
    Navigator.Push(context, MaterialPageRoute(builder: (_) => Page2("Foo")));
    

    Verwenden Sie dies auf der 2. Seite.

    class Page2 extends StatelessWidget {
      final String string;
    
      Page2(this.string); // receiving "Foo" in 2nd
    
      ...
    }
    

  • 2. Seite bis 1. Seite

    Verwenden Sie dies auf der 2. Seite

    // sending "Bar" from 2nd
    Navigator.pop(context, "Bar");
    

    Verwenden Sie dies auf der ersten Seite, es ist dasselbe, das zuvor verwendet wurde, jedoch mit geringen Änderungen.

    // receiving "Bar" in 1st
    String received = await Navigator.Push(context, MaterialPageRoute(builder: (_) => Page2("Foo")));
    
5
CopsOnRoad

Sie können einen dynamic result zurückgeben, wenn Sie den Kontext öffnen, und dann setState((){}) aufrufen, wenn der Wert true ist.

Ich habe einige Codeausschnitte als Referenz eingefügt.

handleClear() async {
    try {
      var delete = await deleteLoanWarning(
        context,
        'Clear Notifications?',
        'Are you sure you want to clear notifications. This action cannot be undone',
      );
      if (delete.toString() == 'true') {
        //call setState here to rebuild your state.

      }
    } catch (error) {
      print('error clearing notifications' + error.toString());
             }
  }



Future<bool> deleteLoanWarning(BuildContext context, String title, String msg) async {

  return await showDialog<bool>(
        context: context,
        child: new AlertDialog(
          title: new Text(
            title,
            style: new TextStyle(fontWeight: fontWeight, color: CustomColors.continueButton),
            textAlign: TextAlign.center,
          ),
          content: new Text(
            msg,
            textAlign: TextAlign.justify,
          ),
          actions: <Widget>[
            new Container(
              decoration: boxDecoration(),
              child: new MaterialButton(
                child: new Text('NO',),
                onPressed: () {
                  Navigator.of(context).pop(false);
                },
              ),
            ),
            new Container(
              decoration: boxDecoration(),
              child: new MaterialButton(
                child: new Text('YES', ),
                onPressed: () {
                  Navigator.of(context).pop(true);
                },
              ),
            ),
          ],
        ),
      ) ??
      false;
}

Viele Grüße Mahi

1
Mahi

Sie können pushReplacement verwenden und die neue Route angeben

1
Sobhan Jachuck

Heute habe ich mich mit der gleichen Situation konfrontiert, aber ich habe es auf viel einfachere Weise gelöst. Ich habe gerade eine globale Variable definiert, die in der ersten stateful-Klasse verwendet wurde. Wenn ich zu einem zweiten stateful-Widget navigiere, lasse ich es den Wert des globalen aktualisieren Variable, die das erste Widget automatisch zur Aktualisierung zwingt. Hier ist ein Beispiel (ich habe es eilig geschrieben, also habe ich kein Gerüst oder eine Material-App installiert, ich wollte nur meinen Standpunkt veranschaulichen): 

import 'package:flutter/material.Dart';
int count = 0 ;

class FirstPage extends StatefulWidget {
FirstPage({Key key}) : super(key: key);

@override
_FirstPageState createState() => _FirstPageState();
}

class _FirstPageState extends State<FirstPage> {
@override
Widget build(BuildContext context) {
return InkWell(
onTap(){
Navigator.of(context).Push(MaterialPageRoute(builder: (context) =>
                  new SecondPage());
},
child: Text('First', style : TextStyle(fontSize: count == 0 ? 20.0 : 12.0)),
),

}


class SecondPage extends StatefulWidget {
SecondPage({Key key}) : super(key: key);

@override
_SecondPageState createState() => _SecondPageState();
}

class _SecondPageState extends State<SecondPage> {
@override
Widget build(BuildContext context) {
return IconButton(
         icon: new Icon(Icons.add),
         color: Colors.amber,
         iconSize: 15.0,
         onPressed: (){
         count++ ;
         },
       ),
     }
0
Mazin Ibrahim

// setze dies dort, wo du auf den zweiten Bildschirm drückst (innerhalb einer asynchronen Funktion)

Function f;
f = await Navigator.pushNamed(context, 'Screenname');
f();

// Setze dies dort, wo du auftauchst

Navigator.pop(context, () {setState(() {});}

// Dies bewirkt, dass die Funktion setState nach dem Aufspringen als Argument an den Bildschirm übergeben wird

0
Mathew Varghese