La structure de mon projet Flutter est la suivante
Main() //Run App with MaterialApp and Routes
L HomePage() //Default route (/), with BottomNavigation
L MoviesPage() //Default BottomNavigation Index and shows a list of movies form TMDB
L DetailsPage()
L SeriesPage()
L SupportPage()
Après avoir cliqué sur n'importe quel film, il accède à DetailsPage (), mais lorsque j'appelle Navigator.pop à partir de DetailsPage (), il devrait revenir à l'écran précédent, mais ce n'est pas le cas.
Le Navigator.canPop (contexte) renvoie false Mais le bouton de retour matériel fonctionne parfaitement, alors comment puis-je le corriger?
main.Dart
class BerryMain extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
home: Inferno(
{
'/': (context, argumets) => HomePage(),
'/detailspage': (context, arguments) => DetailsPage(arguments),
},
).home(context),
);
}
}
page d'accueil
class HomePage extends StatefulWidget {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return _HomePageState();
}
}
class _HomePageState extends State<HomePage> {
int _currentIndex = 0;
final List<Widget> _childnav = [MoviesPage(), SeriesPage(), SupportPage()];
void onTabPressed(...)
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: Text('...'),
actions: <Widget>[
IconButton(
icon: Icon(Icons.search),
onPressed: () {},
)
],
),
body: _childnav[_currentIndex],
bottomNavigationBar: BottomNavigationBar(
onTap: onTabPressed,
currentIndex: _currentIndex, //this property defines current active tab
items: [
BottomNavigationBarItem(
icon: Icon(Icons.movie), title: Text('Movies')),
BottomNavigationBarItem(icon: Icon(Icons.tv), title: Text('Series')),
BottomNavigationBarItem(icon: Icon(Icons.help), title: Text('Help'))
],
),
);
}
}
MoviesPage
//Inside ListView Builder
Virgil.pushNamed(context, '/detailspage', arguments: args);
DétailsPage
//Inside MaterialApp > Scaffold > SliverAppbar > BackButton
Navigator.pop(context)
J'utilise Virgil mais je ne pense pas que ce soit le problème.
Cela peut se produire si votre MoviesPage
a un autre widget MaterialApp
. La plupart du temps, vous souhaitez utiliser Scaffold
comme widget supérieur pour une nouvelle page/écran, mais si vous utilisez accidentellement MaterialApp
à la place, rien ne vous avertit.
Ce qui se passe, c'est que MaterialApp
crée un nouveau Navigator
, donc si vous passez d'une page avec MaterialApp
à une autre, vous avez maintenant deux Navigateurs dans l'arborescence des widgets.
L'appel Navigator.of(context)
recherche le navigateur le plus proche, il utilisera donc celui nouvellement créé dans votre MoviesPage
. Comme l'historique de vos transitions d'itinéraire est stocké dans un premier navigateur, celui-ci ne peut pas revenir en arrière - il a un historique d'itinéraire vide.
Par conséquent, l'écran noir.
Bref, pour résoudre ce problème, utilisez simplement Scaffold
comme widget supérieur au lieu de MaterialApp
dans tous les écrans imbriqués.
Je le résous en utilisant ce code:
Navigator.pushReplacementNamed(context, '/route')
J'ai eu un problème très similaire et ma solution a été de passer BuildContext context du StatelessWidget créé à une variable globale et de faire apparaître ce contexte à partir de la variable globale. Alors...
var globalContext; // Declare global variable to store context from StatelessWidget
class SecondScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
globalContext = context; // globalContext receives context from StetelessWidget.
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
canvasColor: Colors.transparent,
primarySwatch: Colors.blue,
),
home: SecondScreenPage(title: 'SECOND SCREEN'),
);
}
}
class SecondScreenPage extends StatefulWidget {
SecondScreenPage({Key key, this.title}) : super(key: key);
final String title;
@override
_SecondScreenPageState createState() => _SecondScreenPageState();
}
class _SecondScreenPageState extends State<SecondScreenPage>() {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Second Screen"),
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () => Navigator.pop(globalContext), // POPPING globalContext
)
),
...
}
Maintenant, je n'ai pas d'écran noir et je suis sur ma première page comme si j'avais cliqué sur le bouton de retour d'Android. =)
Je ne sais pas si c'est une bonne pratique. Si quelqu'un connaît un moyen de le faire "plus correctement", n'hésitez pas à répondre.
Selon cela Réponse J'ai trouvé un moyen.
Vous devez passer le contexte MoviesPage
au DetailsPage
. Et ce contexte doit être appelé dans Navigator.pop(context);
par exemple: PREMIER ÉCRAN
class FirstScreen extends StatelessWidget {
final BuildContext context;
FirstScreen(this.context);///here u have to call the build Context of FirstScreen
@override
Widget build(BuildContext context) {
return new MaterialApp(
home: FirstScreenScreen(this.context));
}
}
class FirstScreenScreen extends StatefulWidget {
final BuildContext context;
FirstScreenScreen(this.context);/// and here also.
@override
_FirstScreenState createState() => _FirstScreenState();
}
class _FirstScreenState extends State<FirstScreenScreen> {
@override
Widget build(BuildContext context) {
return new Scaffold(
body: Container(
child: new RaisedButton(onPressed: (){
navigateAndDisplaySelection(context);
},
child: new Text('Go to SecondPage'),
),
),
);
}
}
DEUXIÈME ÉCRAN
class SecondScreen extends StatelessWidget {
final BuildContext context;
SecondScreen(this.context);///here u have to call the build Context of FirstScreen
@override
Widget build(BuildContext context) {
return new MaterialApp(
home: SecondScreenScreen(this.context));
}
}
class SecondScreenScreen extends StatefulWidget {
final BuildContext context;
SecondScreenScreen(this.context);/// and here also.
@override
_SecondScreenState createState() => _SecondScreenState();
}
class _SecondScreenState extends State<SecondScreenScreen> {
@override
Widget build(BuildContext context) {
return new Scaffold(
body: Container(
child: new RaisedButton(onPressed: (){
Navigator.pop(widget.context);///this context is passed from firstScreen
},
child: new Text('Go Back'),
),
),
);
}
}
Données de passe et retour
si vous voulez transmettre des données et retourner, ajoutez un constructeur avec un paramètre dans SecondScreen et appelez setState dans la méthode Fisrtlike ceci:
navigateAndDisplaySelection(
BuildContext context) async {
// Navigator.Push returns a Future that will complete after we call
// Navigator.pop on the Second Screen!
Navigator.Push(
context,
MaterialPageRoute(
builder: (context) => new SecondScreen(context)),
);
setState(() {
/// the passed value data will change here, when you change in second screen
});
}
J'ai eu des problèmes similaires lors de l'affichage des vues, la façon dont j'ai corrigé était au lieu de Navigator.of(context).pop();
J'utilise Navigator.of(context).maybePop();
.
Plus d'écrans noirs après ça.