Заменить начальный маршрут в MaterialApp без анимации?

Наше приложение построено поверх Scaffold и к этому моменту мы смогли удовлетворить большинство наших требований к маршрутизации и навигации, используя предоставленные вызовы в NavigatorState (pushNamed(), pushReplacementNamed(), так далее.). Чего мы не хотим, так это иметь какую-либо анимацию "толчка", когда пользователь выбирает элемент из нашего меню ящика (навигация). Мы хотим, чтобы экран назначения из щелчка навигационного меню стал новым начальным маршрутом стека. На данный момент мы используем pushReplacementNamed() для этого, чтобы гарантировать отсутствие стрелки назад на панели приложения. Но анимация скольжения справа показывает, что строится стек.

Каков наш лучший вариант для изменения этого начального маршрута без анимации, и можем ли мы сделать это, одновременно одновременно анимируя закрытый ящик? Или мы рассматриваем ситуацию, когда нам нужно перейти от Navigator к использованию только одного Scaffold и обновлять "body" напрямую, когда пользователь хочет сменить экран?

Мы отмечаем, что есть replace() позвонить на NavigatorState мы предполагаем, что это было бы подходящим местом для начала поиска, но неясно, как получить доступ к нашим различным маршрутам, изначально созданным в new MaterialApp(), Что-то вроде replaceNamed() может быть в порядке;-)

Заранее спасибо!

2 ответа

Решение

То, что вы делаете, звучит как-то BottomNavigationBar так что вы можете рассмотреть один из них вместо Drawer,

Тем не менее, имея один Scaffold и обновление body когда пользователь касается элемента ящика, это вполне разумный подход. Вы могли бы рассмотреть FadeTransition перейти от одного тела к другому.

Или, если вам нравится использовать Navigator но не хотите анимацию слайдов по умолчанию, вы можете настроить (или отключить) анимацию, расширив MaterialPageRoute, Вот пример этого:

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'),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

Ты можешь использовать PageRouteBuilder тоже для этого.

Пример:

@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),
        ),
      );
    },
  );
}

И если вы не хотите иметь анимацию, замените выше transitionsBuilder с

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

Спасибо за невероятно полезный ответ, Коллин!

Небольшой мод, который иногда может быть полезен: по другим причинам я хотел добавить анимацию постепенного появления, когда входил мой экран (Scaffold), но он был в стеке, а когда я выходил, я хотел обычное скольжение вниз, так как был добавлен с помощью Navigator.pushReplacement(...). Невероятно легко добиться этого тоже:

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);
  }
}

Чтобы предотвратить анимацию при отображении маршрута, передайте RouteSettings(isInitialRoute: true) к PageRoute конструктор.

Посмотрите этот ответ с рабочим примером и записью экрана.

Другие вопросы по тегам