web-dev-qa-db-fra.com

Remplacer la route initiale dans MaterialApp sans animation?

Notre application est construite au-dessus de Scaffold et à ce stade, nous avons été en mesure de satisfaire la plupart de nos exigences de routage et de navigation à l'aide des appels fournis dans NavigatorState (pushNamed(), pushReplacementNamed(), etc.). Ce que nous ne voulons pas cependant, c'est d'avoir une sorte d'animation «Push» lorsqu'un utilisateur sélectionne un élément dans notre menu tiroir (nav). Nous voulons que l’écran de destination à partir d’un clic du menu de navigation devienne effectivement le nouvel itinéraire initial de la pile. Pour le moment, nous utilisons pushReplacementNamed () pour éviter des flèches arrière dans la barre des applications. Mais, l’animation par glissement de la droite implique la création d’une pile.

Quelle est notre meilleure option pour changer cette route initiale sans animation, et pouvons-nous le faire tout en animant simultanément le tiroir fermé? Ou sommes-nous en train de nous retrouver dans une situation où nous devons passer de Navigator à un simple échafaudage et à la mise à jour directe du "corps" lorsque l'utilisateur souhaite changer d'écran?

Nous notons qu'il existe un appel replace() sur NavigatorState qui, supposons-nous, pourrait être le bon endroit pour commencer à chercher, mais il est difficile de savoir comment accéder à nos différentes routes initialement configurées dans new MaterialApp(). Quelque chose comme replaceNamed() pourrait être en ordre ;-) 

Merci d'avance!

21
KBDrums

Ce que vous faites sonne un peu comme un BottomNavigationBar , alors vous voudrez peut-être envisager l’un de ceux-ci au lieu d’un Drawer.

Cependant, avoir une seule Scaffold et mettre à jour la body lorsque l'utilisateur appuie sur un tiroir est une approche tout à fait raisonnable. Vous pourriez envisager une FadeTransition pour passer d'un corps à un autre.

Ou, si vous aimez utiliser Navigator mais que vous ne voulez pas l'animation de diapositive par défaut, vous pouvez personnaliser (ou désactiver) l'animation en étendant MaterialPageRoute. Voici un exemple de cela:

import 'package:flutter/material.Dart';

void main() {
  runApp(new MyApp());
}

class MyCustomRoute<T> extends MaterialPageRoute<T> {
  MyCustomRoute({ WidgetBuilder builder, RouteSettings settings })
      : super(builder: builder, settings: settings);

  @override
  Widget buildTransitions(BuildContext context,
      Animation<double> animation,
      Animation<double> secondaryAnimation,
      Widget child) {
    if (settings.isInitialRoute)
      return child;
    // Fades between routes. (If you don't want any animation, 
    // just return child.)
    return new FadeTransition(opacity: animation, child: child);
  }
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Navigation example',
      onGenerateRoute: (RouteSettings settings) {
        switch (settings.name) {
          case '/': return new MyCustomRoute(
            builder: (_) => new MyHomePage(),
            settings: settings,
          );
          case '/somewhere': return new MyCustomRoute(
            builder: (_) => new Somewhere(),
            settings: settings,
          );
        }
        assert(false);
      }
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('Navigation example'),
      ),
      drawer: new Drawer(
        child: new ListView(
          children: <Widget> [
            new DrawerHeader(
              child: new Container(
                  child: const Text('This is a header'),
              ),
            ),
            new ListTile(
              leading: const Icon(Icons.navigate_next),
              title: const Text('Navigate somewhere'),
              onTap: () {
                Navigator.pushNamed(context, '/somewhere');
              },
            ),
          ],
        ),
      ),
      body: new Center(
        child: new Text(
          'This is a home page.',
        ),
      ),
    );
  }
}

class Somewhere extends StatelessWidget {
  Widget build(BuildContext context) {
    return new Scaffold(
      body: new Center(
        child: new Text(
          'Congrats, you did it.',
        ),
      ),
      appBar: new AppBar(
        title: new Text('Somewhere'),
      ),
      drawer: new Drawer(
        child: new ListView(
          children: <Widget>[
            new DrawerHeader(
              child: new Container(
                child: const Text('This is a header'),
              ),
            ),
          ],
        ),
      ),
    );
  }
}
38
Collin Jackson

Merci pour la réponse incroyablement utile, Collin! 

Un petit mod qui pourrait être utile parfois aussi: pour d'autres raisons, je voulais une animation en fondu lorsque mon écran (Scaffold) arrivait, mais c'était sur une pile et lorsque je sortais, je voulais un diaporama a été ajouté avec Navigator.pushReplacement (...). Incroyablement facile à réaliser cela aussi:

class FadeInSlideOutRoute<T> extends MaterialPageRoute<T> {
  FadeInSlideOutRoute({WidgetBuilder builder, RouteSettings settings})
      : super(builder: builder, settings: settings);

  @override
  Widget buildTransitions(BuildContext context, Animation<double> animation,
      Animation<double> secondaryAnimation, Widget child) {
    if (settings.isInitialRoute) return child;
    // Fades between routes. (If you don't want any animation,
    // just return child.)
    if (animation.status == AnimationStatus.reverse)
      return super.buildTransitions(context, animation, secondaryAnimation, child);
    return FadeTransition(opacity: animation, child: child);
  }
}
4
gregko

Vous pouvez aussi utiliser PageRouteBuilder pour cela. 

Exemple:

@override
Widget build(BuildContext context) {
  return RaisedButton(
    onPressed: () {
      Navigator.Push(
        context,
        PageRouteBuilder(
          pageBuilder: (context, anim1, anim2) => SecondScreen(),
          transitionsBuilder: (context, anim1, anim2, child) => FadeTransition(opacity: anim1, child: child),
          transitionDuration: Duration(seconds: 1),
        ),
      );
    },
  );
}

Et si vous ne voulez pas d’animation, remplacez transitionsBuilder ci-dessus par 

transitionsBuilder: (context, anim1, anim2, child) => Container(child: child),
1
CopsOnRoad