Jak widzisz, mój przycisk znajduje się wewnątrz ciała Scaffolda. Ale mam ten wyjątek:
Scaffold.of () wywołano z kontekstem, który nie zawiera 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);
}
EDYTOWAĆ:
Znalazłem inne rozwiązanie tego problemu. Jeśli damy Scaffoldowi klucz, którym jest GlobalKey, możemy wyświetlić SnackBar jako następujący bez potrzeby zawijania naszego ciała widżetem Builder. Jednak widget, który zwraca Scaffold, powinien być widgetem Stateful .:
_scaffoldKey.currentState.showSnackBar(snackbar);
Odpowiedzi:
Ten wyjątek występuje, ponieważ używasz
context
widgetu, którego wystąpienie zostało utworzoneScaffold
. Niecontext
dzieckaScaffold
.Możesz rozwiązać ten problem, używając po prostu innego kontekstu:
Zauważ, że chociaż
Builder
tutaj używamy , nie jest to jedyny sposób na uzyskanie innegoBuildContext
.Możliwe jest również wyodrębnienie poddrzewa do innego
Widget
(zwykle za pomocąextract widget
refaktora)źródło
onPressed
Zdałeś abyRaisedButton
nie jest funkcją. Zmień to na() => _displaySnackBar(context)
Możesz użyć
GlobalKey
. Jedynym minusem jest to, że użycie GlobalKey może nie być najefektywniejszym sposobem zrobienia tego.Dobrą rzeczą jest to, że możesz również przekazać ten klucz do innych niestandardowych klas widżetów, które nie zawierają żadnego szkieletu. Zobacz ( tutaj )
źródło
_scaffoldKey
jest prywatne ze względu na wiodące podkreślenie. Ale nawet gdyby tak nie było, znajduje się wewnątrzHomePage
klasy i dlatego jest niedostępny bez tworzenia wystąpienia nowej strony głównej gdzieś w drzewie, pozornie tworząc cykliczne odwołanie.GlobalKey<ScaffoldState>
właściwością, edytuj konstruktora Widgeta z rusztowaniem, aby ustawić właściwość klucza singletona, a następnie w drzewie widgetu potomnego możemy wywołać coś takiegomySingleton.instance.key.currentState.showSnackBar()
...Dwa sposoby rozwiązania tego problemu
1) Korzystanie z widżetu Builder
2) Korzystanie z GlobalKey
źródło
Sprawdź to w dokumentacji metody:
Możesz sprawdzić opis w dokumentacji metody
źródło
Prostym sposobem rozwiązania tego problemu będzie utworzenie klucza do swojego rusztowania, takiego jak ten finał, z następującym kodem:
Pierwszy:
GlobalKey<ScaffoldState>() _scaffoldKey = GlobalKey<ScaffoldState> ();
Sekunda: przypisz klucz do swojego rusztowania
key: _scaffoldKey
Po trzecie: Zadzwoń do Snackbar za pomocą
_scaffoldKey.currentState.showSnackBar(SnackBar(content: Text("Welcome")));
źródło
To samo zachowanie, którego doświadczasz, jest nawet określane jako „trudny przypadek” w dokumentacji Fluttera .
Jak naprawić
Problem został rozwiązany na różne sposoby, jak widać na podstawie innych odpowiedzi zamieszczonych tutaj. Na przykład dokumentacja, do której się odwołuję, rozwiązuje problem za pomocą pliku
Builder
whichTym samym sposobem rozmowy
showSnackBar
z rusztowań byłobyTeraz trochę szczegółów dla ciekawskiego czytelnika
Sam uznałem za całkiem pouczające zapoznanie się z dokumentacją Fluttera po prostu ( Android Studio ) ustawiając kursor na fragmencie kodu ( klasa Flutter , metoda itp.) I naciskając ctrl + B, aby wyświetlić dokumentację dla tego konkretnego fragmentu.
Konkretny problem , z którym się spotykasz , jest opisany w dokumentacji BuildContext , gdzie można ją przeczytać
Oznacza to więc, że w naszym przypadku kontekst będzie rodzicem naszego widgetu Scaffold po jego utworzeniu (!). Ponadto dokumentacja Scaffold.of mówi, że zwraca
Ale w naszym przypadku kontekst nie obejmuje (jeszcze) rusztowania (nie zostało jeszcze zbudowane). Tam właśnie wkracza Builder !
Po raz kolejny docu nas oświeca. Tam możemy czytać
Hej, chwileczkę, co !? Ok, przyznaję: to niewiele pomaga ... Ale wystarczy powiedzieć (po kolejnym wątku SO )
Więc teraz wszystko staje się jasne! Wywołując Builder wewnątrz Scaffolda , budujemy Scaffold, aby móc uzyskać jego własny kontekst, i uzbrojeni w ten internalContext możemy ostatecznie wywołać Scaffold.of (innerContext)
Poniżej znajduje się opisana wersja powyższego kodu
źródło
Nie zawracałbym sobie głowy używaniem domyślnego paska przekąskowego, ponieważ możesz zaimportować pakiet flushbar, który zapewnia większą możliwość dostosowania:
https://pub.dev/packages/flushbar
Na przykład:
źródło
Bardziej wydajnym rozwiązaniem jest podzielenie funkcji kompilacji na kilka widżetów. Wprowadza to „nowy kontekst”, z którego można uzyskać Scaffold
źródło
Wyodrębnij widżet przycisku, który wyświetli pasek z przekąskami.
źródło
tutaj używamy kreatora do zawijania innego widżetu, w którym potrzebujemy paska przekąskowego
źródło