web-dev-qa-db-fra.com

Comment préserver les états des widgets en flottement lors de la navigation avec BottomNavigationBar?

Je travaille actuellement à la création d'une application Flutter qui préservera les états lors du passage d'un écran à un autre et inversement lors de l'utilisation de BottomNavigationBar . Tout comme cela fonctionne dans l'application mobile Spotify; Si vous avez atteint un certain niveau dans la hiérarchie de navigation sur l’un des écrans principaux, le changement d’écran via la barre de navigation inférieure, puis le retour à l’ancien écran, conserveront la position de l’utilisateur dans cette hiérarchie, notamment l'état.

J'ai couru ma tête contre le mur, essayant diverses choses sans succès.

Je veux savoir comment je peux empêcher les pages dans pageChooser(), lorsqu'elles sont basculées une fois que l'utilisateur appuie sur l'élément BottomNavigationBar, de se reconstruire et de conserver l'état dans lequel il se trouvait déjà (les pages sont toutes des widgets avec état).

import 'package:flutter/material.Dart';
import './page_plan.Dart';
import './page_profile.Dart';
import './page_startup_namer.Dart';

void main() => runApp(new Recipher());

class Recipher extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Pages();
  }
}

class Pages extends StatefulWidget {
  @override
  createState() => new PagesState();
}

class PagesState extends State<Pages> {
  int pageIndex = 0;


  pageChooser() {
    switch (this.pageIndex) {
      case 0:
        return new ProfilePage();
        break;

      case 1:
        return new PlanPage();
        break;

      case 2:
        return new StartUpNamerPage(); 
        break;  

      default:
        return new Container(
          child: new Center(
            child: new Text(
              'No page found by page chooser.',
              style: new TextStyle(fontSize: 30.0)
              )
            ),
          );     
    }
  }

  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      home: new Scaffold(
        body: pageChooser(),
        bottomNavigationBar: new BottomNavigationBar(
          currentIndex: pageIndex,
          onTap: (int tappedIndex) { //Toggle pageChooser and rebuild state with the index that was tapped in bottom navbar
            setState(
              (){ this.pageIndex = tappedIndex; }
              ); 
            },
          items: <BottomNavigationBarItem>[
            new BottomNavigationBarItem(
              title: new Text('Profile'),
              icon: new Icon(Icons.account_box)
              ),
              new BottomNavigationBarItem(
                title: new Text('Plan'),
                icon: new Icon(Icons.calendar_today)
              ),
                new BottomNavigationBarItem(
                title: new Text('Startup'),
                icon: new Icon(Icons.alarm_on)
              )
            ],
          )
      )
    );
  }
}
8
ArtBelch

Utilisez AutomaticKeepAliveClientMixin pour forcer le contenu de votre onglet à ne pas être supprimé.

class PersistantTab extends StatefulWidget {
  @override
  _PersistantTabState createState() => _PersistantTabState();
}

class _PersistantTabState extends State<PersistantTab> with AutomaticKeepAliveClientMixin {
  @override
  Widget build(BuildContext context) {
    return Container();
  }

  // Setting to true will force the tab to never be disposed. This could be dangerous.
  @override
  bool get wantKeepAlive => true;
}

Pour vous assurer que votre onglet est éliminé lorsqu'il n'est pas nécessaire de le conserver, faites en sorte que wantKeepAlive renvoie une variable de classe. Vous devez appeler updateKeepAlive() pour mettre à jour le statut Keep Alive.

Exemple avec dynamique Keep Alive:

// class PersistantTab extends StatefulWidget ...

class _PersistantTabState extends State<PersistantTab>
    with AutomaticKeepAliveClientMixin {
  bool keepAlive = false;

  @override
  void initState() {
    doAsyncStuff();
  }

  Future doAsyncStuff() async {
    keepAlive = true;
    updateKeepAlive();
    // Keeping alive...

    await Future.delayed(Duration(seconds: 10));

    keepAlive = false;
    updateKeepAlive();
    // Can be disposed whenever now.
  }

  @override
  bool get wantKeepAlive => keepAlive;

  @override
  Widget build(BuildContext context) {
    return Container();
  }
}
2
Charles Crete

Au lieu de renvoyer une nouvelle instance chaque fois que vous exécutez pageChooser, faites-en créer une et renvoyez la même.

Exemple:

class Pages extends StatefulWidget {
  @override
  createState() => new PagesState();
}

class PagesState extends State<Pages> {
  int pageIndex = 0;

  // Create all the pages once and return same instance when required
  final ProfilePage _profilePage = new ProfilePage(); 
  final PlanPage _planPage = new PlanPage();
  final StartUpNamerPage _startUpNamerPage = new StartUpNamerPage();


  Widget pageChooser() {
    switch (this.pageIndex) {
      case 0:
        return _profilePage;
        break;

      case 1:
        return _planPage;
        break;

      case 2:
        return _startUpNamerPage;
        break;

      default:
        return new Container(
          child: new Center(
              child: new Text(
                  'No page found by page chooser.',
                  style: new TextStyle(fontSize: 30.0)
              )
          ),
        );
    }
  }

  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
        home: new Scaffold(
            body: pageChooser(),
            bottomNavigationBar: new BottomNavigationBar(
              currentIndex: pageIndex,
              onTap: (int tappedIndex) { //Toggle pageChooser and rebuild state with the index that was tapped in bottom navbar
                setState(
                        (){ this.pageIndex = tappedIndex; }
                );
              },
              items: <BottomNavigationBarItem>[
                new BottomNavigationBarItem(
                    title: new Text('Profile'),
                    icon: new Icon(Icons.account_box)
                ),
                new BottomNavigationBarItem(
                    title: new Text('Plan'),
                    icon: new Icon(Icons.calendar_today)
                ),
                new BottomNavigationBarItem(
                    title: new Text('Startup'),
                    icon: new Icon(Icons.alarm_on)
                )
              ],
            )
        )
    );
  }
}

Ou vous pouvez utiliser des widgets tels que PageView ou Stack pour obtenir le même résultat.

J'espère que cela pourra aider!

0
Hemanth Raj