flutter: анимировать переход к названному маршруту

Когда я использую Navigator.pushNamed(context, "/someRoute");, появляется минимальная анимация, которая скользит по новому маршруту снизу экрана (на Android может выглядеть иначе на iOS).

Как я могу добавить к этому переходу собственную анимацию?

Я нашел эту статью, в котором есть отличный пример кода для безымянных маршрутов. Они реализуют свой собственный класс, который наследуется от PageRouteBuilder и может использоваться следующим образом: Navigator.push(context, SlideRightRoute(page: Screen2())). Но PageRouteBuilder не является виджетом и не может быть зарегистрирован как маршрут в MaterialApp. Поэтому я не понимаю, как применить это к именованным маршрутам.


person lhk    schedule 27.06.2019    source источник
comment
использовать свойство onGenerateRoute   -  person pskink    schedule 27.06.2019


Ответы (3)


Вам необходимо использовать onGenerateRoute в своем виджете MaterialApp.

onGenerateRoute: (settings) {
  if (settings.name == "/someRoute") {
    return PageRouteBuilder(
      settings: settings, // Pass this to make popUntil(), pushNamedAndRemoveUntil(), works
      pageBuilder: (_, __, ___) => SomePage(),
      transitionsBuilder: (_, a, __, c) => FadeTransition(opacity: a, child: c)
    );
  }
  // Unknown route
  return MaterialPageRoute(builder: (_) => UnknownPage());
},
person CopsOnRoad    schedule 27.06.2019
comment
У меня это сработало. Единственное, что я хотел бы добавить, - это settings, который нужно передать конструктору PageRouteBuilder, чтобы были включены аргументы маршрута. Вот что у меня получилось: `` onGenerateRoute: (settings) = ›PageRouteBuilder (pageBuilder: (context, , __) =› routes [settings.name] (context), settings: settings, transitionsBuilder: ( , animation1, __, child) = ›FadeTransition (opacity: animation1, child: child),),` ` - person Your Friend Ken; 04.10.2019
comment
Кроме того, если вы установите routes на MaterialApp, он игнорирует onGenerateRoute - person Your Friend Ken; 04.10.2019
comment
Если я использую это, URL-адрес вверху больше не отображает новое имя маршрута. Разве это не проблема, если я хочу сказать, что используйте pushNamedAndRemoveUntil ()? - person Eradicatore; 11.02.2020
comment
Это самый простой и лучший ответ о том, как настроить минимальный переход между страницами. Просто хорошо. Спасибо. - person devdanke; 27.06.2020

Использование анимированных маршрутов возможно без onGenerateRoute!

Если вы используете routes карту MaterialApp для определения именованных маршрутов, вот как вы можете определить именованный маршрут (имя которого не будет null).

Просто создайте свой маршрут, расширив PageRouteBuilder:

import 'package:flutter/material.dart';

class FadeInRoute extends PageRouteBuilder {
  final Widget page;

  FadeInRoute({this.page, String routeName})
      : super(
          settings: RouteSettings(name: routeName),            // set name here
          pageBuilder: (
            BuildContext context,
            Animation<double> animation,
            Animation<double> secondaryAnimation,
          ) =>
              page,
          transitionsBuilder: (
            BuildContext context,
            Animation<double> animation,
            Animation<double> secondaryAnimation,
            Widget child,
          ) =>
              FadeTransition(
            opacity: animation,
            child: child,
          ),
          transitionDuration: Duration(milliseconds: 500),
        );
}

а затем, когда вы путешествуете, просто сделайте:

Navigator.push( // or pushReplacement, if you need that
  context,
  FadeInRoute(
    routeName: RouteNames.home,
    page: MyHomeScreen(),
  ),
);
person Aleksandar    schedule 18.01.2021
comment
Можете ли вы объяснить, как передать аргумент FadeInRoute в Navigator.pushNamed в качестве второго параметра, когда ожидается String? - person Mike Kokadii; 28.01.2021
comment
@MikeKokadii Я думаю, что @Alexandar хотел использовать Navigator.push(). Этот метод отлично подходит для перехода к заранее определенному виджету по заданному имени маршрута. Однако вам необходимо предоставить виджет для этой страницы самостоятельно. Если вы ищете простой способ сделать хорошую замену перехода для Navigator.pushNamed(....), это не то. - person Max; 29.01.2021
comment
@Max, спасибо, что указали на это! Это определенно была ошибка. В моем исходном коде я использовал pushReplacement, поэтому я, вероятно, неправильно его прочитал, когда писал это. Ответ теперь отредактирован :) - person Aleksandar; 29.01.2021
comment
@MikeKokadii, пожалуйста, проверьте, работает ли это для вас сейчас :) - person Aleksandar; 29.01.2021

Я нашел простое решение (вдохновленное этим кодом)

Во-первых, вам нужно установить статический GlobalKey для MaterialApp и экспортировать его.

static GlobalKey mtAppKey = GlobalKey();

Widget build(BuildContext context) {
  return MaterialApp(
    key: MyApp.mtAppKey,
    ...

Кроме того, вам потребуется собственный PageRouteBuilder, чтобы справиться с этим.

Нуль-безопасность отключена

class CustomNamedPageTransition extends PageRouteBuilder {
  CustomNamedPageTransition(
    GlobalKey materialAppKey,
    String routeName, {
    Object arguments,
  }) : super(
          settings: RouteSettings(
            arguments: arguments,
            name: routeName,
          ),
          pageBuilder: (
            BuildContext context,
            Animation<double> animation,
            Animation<double> secondaryAnimation,
          ) {
            assert(materialAppKey.currentWidget != null);
            assert(materialAppKey.currentWidget is MaterialApp);
            var mtapp = materialAppKey.currentWidget as MaterialApp;
            var routes = mtapp.routes;
            assert(routes.containsKey(routeName));
            return routes[routeName](context);
          },
          transitionsBuilder: (
            BuildContext context,
            Animation<double> animation,
            Animation<double> secondaryAnimation,
            Widget child,
          ) =>
              FadeTransition(
            opacity: animation,
            child: child,
          ),
          transitionDuration: Duration(seconds: 1),
        );
}

Включена нулевая безопасность

class CustomNamedPageTransition extends PageRouteBuilder {
  CustomNamedPageTransition(
    GlobalKey materialAppKey,
    String routeName, {
    Object? arguments,
  }) : super(
          settings: RouteSettings(
            arguments: arguments,
            name: routeName,
          ),
          pageBuilder: (
            BuildContext context,
            Animation<double> animation,
            Animation<double> secondaryAnimation,
          ) {
            assert(materialAppKey.currentWidget != null);
            assert(materialAppKey.currentWidget is MaterialApp);
            var mtapp = materialAppKey.currentWidget as MaterialApp;
            var routes = mtapp.routes;
            assert(routes!.containsKey(routeName));
            return routes![routeName]!(context);
          },
          transitionsBuilder: (
            BuildContext context,
            Animation<double> animation,
            Animation<double> secondaryAnimation,
            Widget child,
          ) =>
              FadeTransition(
            opacity: animation,
            child: child,
          ),
          transitionDuration: Duration(seconds: 1),
        );
}

Затем вы можете открыть свой именованный маршрут с помощью

Navigator.push(
  context,
  CustomNamedPageTransition(
    MyApp.mtAppKey,
    MyRoute.routeName,
  ),
);

or

Navigator.pushReplacement(
  context,
  CustomNamedPageTransition(
    MyApp.mtAppKey,
    MyRoute.routeName,
  ),
);
person Furkan Karcıoğlu    schedule 22.06.2021