Показать 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!')
)
);