web-dev-qa-db-ja.com

Scaffoldを含まないコンテキストでScaffold.of()が呼び出されました

ご覧のとおり、私のボタンは足場の中にあります。しかし、私はこの例外が出ます:

Scaffold.of()がScaffoldを含まないコンテキストで呼び出されました。

import 'package:flutter/material.Dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: HomePage(),
    );
  }
}

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('SnackBar Playground'),
      ),
      body: Center(
        child: RaisedButton(
          color: Colors.pink,
          textColor: Colors.white,
          onPressed: _displaySnackBar(context),
          child: Text('Display SnackBar'),
        ),
      ),
    );
  }
}

_displaySnackBar(BuildContext context) {
  final snackBar = SnackBar(content: Text('Are you talkin\' to me?'));
  Scaffold.of(context).showSnackBar(snackBar);
}

編集:

私はこの問題に対する別の解決策を見つけました。 ScaffoldにGlobalKeyというキーを指定すれば、ボディをBuilderウィジェットでラップする必要なく、SnackBarを次のように表示できます。 Scaffoldを返すウィジェットは、ステートフルなウィジェットであるべきです。

 _scaffoldKey.currentState.showSnackBar(snackbar); 
57
Figen Güngör

この例外は、contextをインスタンス化したウィジェットのScaffoldを使用しているために発生します。 contextの子のScaffoldではありません。

これを解決するには、異なるコンテキストを使用します。

Scaffold(
    appBar: AppBar(
        title: Text('SnackBar Playground'),
    ),
    body: Builder(
        builder: (context) => 
            Center(
            child: RaisedButton(
            color: Colors.pink,
            textColor: Colors.white,
            onPressed: () => _displaySnackBar(context),
            child: Text('Display SnackBar'),
            ),
        ),
    ),
);

ここではBuilderを使用していますが、これが別のBuildContextを取得する唯一の方法ではありません。

サブツリーを別のWidgetに抽出することもできます(通常はextract widgetリファクタを使用)。

78
Rémi Rousselet

GlobalKeyを使用できます。唯一の欠点は、GlobalKeyを使用するのが最も効率的な方法ではないかもしれないということです。

これについて良いことは、スキャフォールドを含まない他のカスタムウィジェットクラスにもこのキーを渡すことができるということです。 ( ここ )を参照

class HomePage extends StatelessWidget {
  final _scaffoldKey = GlobalKey<ScaffoldState>(); \\ new line
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      key: _scaffoldKey,                           \\ new line
      appBar: AppBar(
        title: Text('SnackBar Playground'),
      ),
      body: Center(
        child: RaisedButton(
          color: Colors.pink,
          textColor: Colors.white,
          onPressed: _displaySnackBar(context),
          child: Text('Display SnackBar'),
        ),
      ),
    );
  }
}

_displaySnackBar(BuildContext context) {
  final snackBar = SnackBar(content: Text('Are you talkin\' to me?'));
  _scaffoldKey.currentState.showSnackBar(snackBar);   \\ edited line
}
29
Lebohang Mbele

Methodのドキュメントからこれを確認してください。

足場が実際に同じビルド関数で作成されるとき、ビルド関数へのコンテキスト引数は足場を見つけるのに使用することができません(それが返されるウィジェットの「上」にあるので)。このような場合は、以下のBuilderのテクニックを使用して、足場の「下」にあるBuildContextを使用して新しいスコープを提供できます。

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: Text('Demo')
    ),
    body: Builder(
      // Create an inner BuildContext so that the onPressed methods
      // can refer to the Scaffold with Scaffold.of().
      builder: (BuildContext context) {
        return Center(
          child: RaisedButton(
            child: Text('SHOW A SNACKBAR'),
            onPressed: () {
              Scaffold.of(context).showSnackBar(SnackBar(
                content: Text('Hello!'),
              ));
            },
          ),
        );
      },
    ),
  );
}

説明は メソッドの docsから確認できます。

2
SANAT