1. ホーム
  2. flutter

[解決済み] ポップアップ時にFlutterナビゲータの状態を再読み込みするように強制する

2022-04-21 02:51:48

質問

私は1つ持っています StatefulWidget を持つFlutterで、このボタンが別の StatefulWidget を使って Navigator.push() . 2番目のウィジェットでは、グローバルな状態(いくつかのユーザー設定)を変更しています。2 番目のウィジェットから 1 番目のウィジェットに戻るときに Navigator.pop() 最初のウィジェットは古い状態ですが、強制的に再読み込みしたいのです。どうすればいいのでしょうか?私は一つのアイデアを持っていますが、それは醜く見えます。

  1. 2番目のウィジェット(現在のウィジェット)を削除するポップ
  2. 最初のウィジェット(前のウィジェット)を削除するには、もう一度ポップします。
  3. 最初のウィジェットを押す (強制的に再描画する)

解決するには?

ここでできることは2つあります。Mahiさんの回答は正しいのですが、もう少し簡潔で、OPが質問したshowDialogではなく、実際にpushを使っています。これは Navigator.push :

import 'package:flutter/material.dart';

class SecondPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.green,
      child: Column(
        children: <Widget>[
          RaisedButton(
            onPressed: () => Navigator.pop(context),
            child: 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: Column(
        children: <Widget>[
          RaisedButton(
            child: Text("next"),
            onPressed: () async {
              final value = await Navigator.push(
                context,
                MaterialPageRoute(
                  builder: (context) => SecondPage()),
                ),
              );
              setState(() {
                color = color == Colors.white ? Colors.grey : Colors.white;
              });
            },
          ),
        ],
      ),
    );
  }
}

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

しかし、あなたのユースケースによく合うかもしれない、別の方法があります。もしあなたが global を最初のページのビルドに影響を与えるものとして使用することができます。 継承されたウィジェット を使用してグローバルなユーザープリファレンスを定義し、それらが変更されるたびにFirstPageが再構築されます。これは、以下に示すように、ステートレスウィジェット内でも動作します (ただし、ステートフルウィジェットでも動作するはずです)。

flutterのinheritedWidgetの例として、アプリのThemeがありますが、このように直接ビルドさせるのではなく、ウィジェット内で定義しています。

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

class SecondPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.green,
      child: Column(
        children: <Widget>[
          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(),
      ),
    );

継承されたウィジェットを使用すれば、プッシュしたページのポップアップを監視する心配はありません。これは基本的なユースケースには有効ですが、より複雑なシナリオでは問題が発生する可能性があります。