Scaffold.of() called with a context that does not contain a Scaffold

半城伤御伤魂 提交于 2019-12-17 15:24:01

问题


As you can see my button is inside Scaffold's body. But I get this exception:

Scaffold.of() called with a context that does not contain a 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);
}

EDIT:

I found an another solution to this problem. If we give Scaffold a key which is GlobalKey, we can display the SnackBar as following without need to wrap our body with Builder widget. The widget which return Scaffold should be Stateful widget though.:

 _scaffoldKey.currentState.showSnackBar(snackbar); 

回答1:


This exception happens because you are using the context of the widget that instantiated Scaffold. Not the context of a child of Scaffold.

You can solve this by just using a different context :

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'),
            ),
        ),
    ),
);

Note that while we're using Builder here, this is not the only way to obtain a different BuildContext.

It is also possible to extract the subtree into a different Widget (usually using extract widget refactor)




回答2:


You can use a GlobalKey. The only downside is that using GlobalKey might not be the most efficient way of doing this.

A good thing about this is that you can also pass this key to other custom widgets class that do not contain any scaffold. See(here)

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
  }
}



回答3:


There is two way to solve this problem

1) Using Builder widget

Scaffold(
    appBar: AppBar(
        title: Text('My Profile'),
    ),
    body: Builder(
        builder: (ctx) => RaisedButton(
            textColor: Colors.red,
            child: Text('Submit'),
            onPressed: () =>  Scaffold.of(ctx).showSnackBar(SnackBar(content: Text('Profile Save'),
            ),
        ),
    ),
);

2) Using GlobalKey

class HomePage extends StatelessWidget {
  final globalKey = GlobalKey<ScaffoldState>(); 
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      key: globalKey,       
      appBar: AppBar(
        title: Text('My Profile'),
      ),
      body:  RaisedButton(
          textColor: Colors.red,
          child: Text('Submit'),
          onPressed: showSnackbar(context),
        ),
      ),
    );
  }
}

void showSnackbar(BuildContext context) {
  final snackBar = SnackBar(content: Text('Profile saved'));
  globalKey.currentState.showSnackBar(snackBar);  
}



回答4:


Check this from the documentation of method:

When the Scaffold is actually created in the same build function, the context argument to the build function can't be used to find the Scaffold (since it's "above" the widget being returned). In such cases, the following technique with a Builder can be used to provide a new scope with a BuildContext that is "under" the Scaffold:

@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!'),
              ));
            },
          ),
        );
      },
    ),
  );
}

You can check the description from the of method docs




回答5:


Simple way to solving this issue will be creating a key for your scaffold like this final with the following code:

First: GlobalKey<ScaffoldState>() _scaffoldKey = GlobalKey<ScaffoldState> ();

Scecond: Assign the Key to your Scaffold key: _scaffoldKey

Third: Call the Snackbar using _scaffoldKey.currentState.showSnackBar(SnackBar(content: Text("Welcome")));



来源:https://stackoverflow.com/questions/51304568/scaffold-of-called-with-a-context-that-does-not-contain-a-scaffold

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!