Показать SnackBar в Flutter

Я хочу отобразить простой SnackBar внутри флаттера с сохранением состояния. Мое приложение создает новый экземпляр MaterialApp с виджетами с состоянием MyHomePage.

Я пытаюсь показать метод SnackBar в методе showSnackBar(). Но он терпит неудачу с "Метод showSnackBar" был вызван на null.

Что не так с этим кодом?

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

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

  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();

  @override
  void initState() {
    super.initState();
    showInSnackBar("Some text");
  }

  @override
  Widget build(BuildContext context) {
    return new Padding(
            key: _scaffoldKey,
            padding: const EdgeInsets.all(16.0),
            child: new Text("Simple Text")
    );
  }

  void showInSnackBar(String value) {
    _scaffoldKey.currentState.showSnackBar(new SnackBar(
        content: new Text(value)
    ));
  }
}

РЕШЕНИЕ:

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

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

  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    showInSnackBar("Some text");
    return new Padding(
        padding: const EdgeInsets.all(16.0),
        child: new Scaffold(
          body: new Text("Simple Text")
        )
    );
  }

  void showInSnackBar(String value) {
    Scaffold.of(context).showSnackBar(new SnackBar(
        content: new Text(value)
    ));
  }
}

Ответ 1

Там три проблемы. Во-первых, у вас нет леса в любом месте, а виджет Scaffold - тот, кто знает, как показывать закуски. Во-вторых, у вас есть ключ для захвата эшафота, но вместо этого вы положили его на Padding (а Paddings не знают о закусках). В-третьих, вы использовали ключ до того, как виджет, с которым он ассоциировался, имел возможность инициализироваться, поскольку initState вызывается перед сборкой.

Самое простое решение - изменить строку home в виджетах MyApp на:

home: new Scaffold(body: new MyHomePage()),

... и затем удалите все упоминания _scaffoldKey и вместо этого используйте Scaffold.of(context), где у вас есть _scaffoldKey.currentState.

Ответ 2

В моем случае у меня был такой код (в состоянии класса)

final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();

void showInSnackBar(String value) {
    _scaffoldKey.currentState.showSnackBar(new SnackBar(content: new Text(value)));
}

но я не настроил ключ для эшафот. поэтому, когда я добавлю ключ: _scaffoldKey

 @override
 Widget build(BuildContext context) {
  return new Scaffold(
    key: _scaffoldKey,
    body: new SafeArea(

закусочная начинает работать :)

Ответ 3

Есть лучший и более чистый способ отображать снэк-бар в трепетании. Я нашел это трудным путем и делиться, так что, может быть, это полезно для кого-то еще.

Не нужно менять в основной части приложения

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
  return new MaterialApp(
    title: 'MyApp',
    theme: new ThemeData(
    primarySwatch: Colors.orange),
    home: new MainPage());
  }
}

Код состояния страницы - это то, где все изменится.

Мы знаем, что Flutter предоставляет Scaffold.of(context).showSnackBar. Однако контекст должен быть контекстом потомка скаффолда, а не контекстом, включающим скаффолд. Чтобы избежать ошибок, нам нужно использовать BuildContext для тела Scaffold и сохранить его в переменной, как показано ниже.

class MainPageState extends State<MainPage> {                                                                         
BuildContext scaffoldContext;                                                                                                                                                                                                

@override                                                                                                           
Widget build(BuildContext context) {                                                                                

return new Scaffold(                                                                                              
    backgroundColor: Colors.grey,                                                                                 
    appBar: new AppBar(                                                                                           
      title: const Text(APP_TITLE),                                                                               
    ),                                                                                                             
    body: new Builder(builder: (BuildContext context) {                                                           
      scaffoldContext = context;                                                                                  
      return new Center(
           child: new Text('Hello World', style: new TextStyle(fontSize: 32.0)),
         );                                                                                
    }));                                                                                                           
}                                                                                                                   


void createSnackBar(String message) {                                                                               
  final snackBar = new SnackBar(content: new Text(message),                                                         
  backgroundColor: Colors.red);                                                                                      

  // Find the Scaffold in the Widget tree and use it to show a SnackBar!                                            
  Scaffold.of(scaffoldContext).showSnackBar(snackBar);                                                              
  }                                                                                                                   
}     

Теперь вы можете вызвать эту функцию из любой точки мира, и она отобразит снэк-бар. Например, я использую его для отображения сообщений о подключении к Интернету.

Ответ 4

Я делаю это, работа для меня :)

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

Ответ 5

initState вызывается до build Я думаю, _scaffoldKey.currentState не был инициализирован, когда он является вызовом.

Я не знаю, можете ли вы получить ScaffoldState из initState. Если вы измените свой код, вы можете показать snackbar из build с помощью:

Scaffold.of(context).showSnackBar(new SnackBar(new Text(value)));

Ответ 6

В случае, если кто-то хочет инициализировать Snackbar в initState() (другими словами, когда страница загружается, вот мое решение). Кроме того, я предполагаю, что у вас уже есть _scaffoldKey.

void initState() {
  super.initState();
  Future.delayed(Duration(seconds: 1)).then(
    (_) => _displaySnackbar
  );
}

// Display Snackbar
void get _displaySnackbar {
  _scaffoldKey.currentState.showSnackBar(SnackBar(
    duration: Duration(minutes: 1),
    content: Text('Your snackbar message')
  ));
}

Ответ 7

Для инициализации Snackbar в initState() вы можете выполнить функцию после построения макета.

void initState() {
super.initState();
WidgetsBinding.instance
    .addPostFrameCallback((_) => _scaffoldKey.currentState.showSnackBar(SnackBar(content: Text("Your message here..")));}

Ответ 8

Scaffold.of(context).showSnackBar(
     SnackBar(content: Text("Thanks for using snackbar",
     textAlign: TextAlign.center, style: TextStyle(fontSize: 16.0, fontWeight: 
     FontWeight.bold),), duration: Duration(seconds: 2), backgroundColor: Colors.red,)
);

Ответ 9

Вы можете использовать это:

final _scaffoldKey = GlobalKey<ScaffoldState>();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      key: _scaffoldKey,
      appBar: AppBar(


    ),
  }
}

а потом в onPressed() можно добавить этот код

_scaffoldKey.currentState.showSnackBar(
       new SnackBar(
          content: new Text('Hello this is snackbar!')
       )
);