web-dev-qa-db-ja.com

Flutterのダイアログでプロバイダープロバイダーにアクセスする方法

プロバイダーパッケージはInheritedWidgetを使用します。これは、ダイアログにいるときにプロバイダーにアクセスしたい場合の問題です。を使用してダイアログをロードした場合

 showDialog(... builder: (context) => MyDialog);

ダイアログがメインウィジェットツリーの一部ではないため、InheritedWidgetを使用して何にもアクセスできません。これは、プロバイダープロバイダーにアクセスできないことも意味しますよね?

私の質問は、メインアプリウィジェットツリーの一部ではない場合、ダイアログでプロバイダーにアクセスするにはどうすればよいですか?

final firebaseAuth = Provider.of<FirebaseAuth>(context);

BLoCsの使用に関しても同じ問題があります。 InheritedWidgetを使用してダイアログでそれらを取得しようとすると、失敗します。コンストラクタでBLoCを渡すことでこれを回避しましたが、これはInheritedWidgetsの目的に反するようです。

4

データセットをアラートダイアログに渡すことで、プロバイダーデータにアクセスできました。興味深いことに、ダイアログの変更を確認するには、ダイアログでsetState()を呼び出す必要があります。

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {

    final provider = Provider.of<DataSet>(context);

    return Scaffold(
      body: Container(
        child: RaisedButton(
        child: Text('Show Dialog'),
          onPressed: () {
            showDialog(context: context,
            builder: (context) {
              return DialogContent(dataSet: provider);
            });
          },
        ),
      ),
    );
  }
}

class DialogContent extends StatefulWidget {

  final DataSet dataSet;

  const DialogContent({Key key, this.dataSet}) : super(key: key);

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

class _DialogContentState extends State<DialogContent> {
  @override
  Widget build(BuildContext context) {
    return AlertDialog(
      title: Text('Dialog with data'),
      content: Text('${widget.dataSet.pieceOfData}'),
      actions: <Widget>[
        FlatButton(
          child: Text('Increase Data'),
          onPressed: () {
            setState(() {
              widget.dataSet.increaseData();
            });
          },
        ),
      ],
    );
  }
}

class DataSet with ChangeNotifier {
  int pieceOfData = 1;

  increaseData() {
    pieceOfData += 1;
    notifyListeners();
  }
}
0
Eric Duffett

ダイアログの新しいコンテキストでアクセスするには、提供されているものを直接ダイアログコンストラクターに渡す必要があります。また、ダイアログに非常に深いウィジェットツリーがあり、より深いところからアクセスしたい場合は、ダイアログツリーの上部にある新しいプロバイダーウィジェットにそれを与えることもできます。

Blocを使用している場合は、通常、プロバイダーウィジェットが破棄されてストリームコントローラー/サブスクリプションをクリーンアップするときに、Blocのdisposeメソッドを呼び出すようにプロバイダーに指示します。明らかに、ブロックをダイアログに再提供している場合、またはこのブロックがダイアログの外部で使用されている場合は、これを実行したくない場合があります。

ダイアログでステートフルまたはステートレスウィジェットを使用するかどうかは、ブロックにアクセスできる限り、streambuilderを使用して、通常どおりストリームを聞くことができます。

例:

class EditEventDialog extends StatelessWidget {

  final GroupBloc groupBloc;

  EditEventDialog({this.groupBloc})
      : assert(groupBloc != null);

  @override
  Widget build(BuildContext context) {
    return Provider(
      builder: (context) => groupBloc,
      child: Dialog(
        child: Container(
          height: 400.0,
          width: 200.0,
          child: StreamBuilder<StatusStreamType>(
            stream: groupBloc.statusStream,
            builder: (context, snapshot) {
    ....

それを呼び出すには:

onPressed: () => showDialog(
                    builder: (newContext) {
                      GroupBloc groupBloc = Provider.of<GroupBloc>(context);
                      return EditEventDialog(
                        groupBloc: groupBloc,
                      );
                    },
                    context: context,
                  )
0
Kris