Будущих учащихся на курсе «Flutter Mobile Developer» и всех интересующихся приглашаем записаться на открытый онлайн-урок по теме «Графика во Flutter». На уроке участники вместе с экспертом-ведущим разберут, как устроен рендеринг во Flutter и изучат основные компоненты библиотеки dart:ui.

А сейчас делимся с вами традиционным переводом интересного материала.


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

Открыть страницу по маршруту:

Navigator.push(
    context,
    MaterialPageRoute(builder: (context) => SecondRoute()),
  );

Закрыть текущую страницу:

Navigator.pop(context);

Вот так. Но… Это очень скучно, нет никакой анимации.

В Winkl, когда мы начали экспериментировать с анимацией, то поняли, что переход с одной страницы на другую может сделать ваш пользовательский интерфейс действительно красивым. Если вы хотите получить слайд-переход, такой же как в IOS, вы используете CupertinoPageRoute. Вот и все, ничего больше.

Navigator.push(

   context, CupertinoPageRoute(builder: (context) => Screen2()))

Но для пользовательской настройки перемещения Flutter предоставляет различные виджеты  этого типа. Давайте посмотрим, как мы можем их использовать.

Мы знаем, что Navigator.push использует два аргумента (BuildContext context, Route<T> route). Мы можем создать свой собственный маршрут перехода по страницам с некоторой анимацией. Давайте начнем с чего-нибудь простого, вроде слайд-перехода.

Слайд-переход (Slide Transition)

Мы дополним PageRouteBuilder и установим параметр transitionBuilder - в результате получаем виджет слайд-перехода (SlideTransition). Виджет SlideTransition использует позицию типа Animation <Offset>. Мы будем использовать значение Tween <Offset> для задания начального и конечного положения .

import 'package:flutter/material.dart';
class SlideRightRoute extends PageRouteBuilder {
  final Widget page;
  SlideRightRoute({this.page})
      : super(
          pageBuilder: (
            BuildContext context,
            Animation<double> animation,
            Animation<double> secondaryAnimation,
          ) =>
              page,
          transitionsBuilder: (
            BuildContext context,
            Animation<double> animation,
            Animation<double> secondaryAnimation,
            Widget child,
          ) =>
              SlideTransition(
                position: Tween<Offset>(
                  begin: const Offset(-1, 0),
                  end: Offset.zero,
                ).animate(animation),
                child: child,
              ),
        );
}

Теперь мы можем использовать SlideRightRoute вместо MaterialPageRoute вот так.

Navigator.push(context, SlideRightRoute(page: Screen2()))

В результате…

Довольно просто, не так ли? Вы можете изменить направление слайд-перехода, изменив значение смещения.

Масштабирование перехода (Scale Transition)

Scale Transition анимирует масштаб преобразованного виджета. Вы также можете изменить способ анимации, изменив кривые CurvedAnimation. В приведенном ниже примере я использовал Curves.fastOutSlowIn.

import 'package:flutter/material.dart';
class ScaleRoute extends PageRouteBuilder {
  final Widget page;
  ScaleRoute({this.page})
      : super(
          pageBuilder: (
            BuildContext context,
            Animation<double> animation,
            Animation<double> secondaryAnimation,
          ) =>
              page,
          transitionsBuilder: (
            BuildContext context,
            Animation<double> animation,
            Animation<double> secondaryAnimation,
            Widget child,
          ) =>
              ScaleTransition(
                scale: Tween<double>(
                  begin: 0.0,
                  end: 1.0,
                ).animate(
                  CurvedAnimation(
                    parent: animation,
                    curve: Curves.fastOutSlowIn,
                  ),
                ),
                child: child,
              ),
        );
}

В результате…

Переход с вращением (Rotation Transition)

Такой переход позволяет осуществить вращение в виджете. Вы также можете включить параметр transitionDuration в ваш виджет PageRouteBuilder.

import 'package:flutter/material.dart';
class RotationRoute extends PageRouteBuilder {
  final Widget page;
  RotationRoute({this.page})
      : super(
          pageBuilder: (
            BuildContext context,
            Animation<double> animation,
            Animation<double> secondaryAnimation,
          ) =>
              page,
          transitionDuration: Duration(seconds: 1),
          transitionsBuilder: (
            BuildContext context,
            Animation<double> animation,
            Animation<double> secondaryAnimation,
            Widget child,
          ) =>
              RotationTransition(
                turns: Tween<double>(
                  begin: 0.0,
                  end: 1.0,
                ).animate(
                  CurvedAnimation(
                    parent: animation,
                    curve: Curves.linear,
                  ),
                ),
                child: child,
              ),
        );
}

В результате…

Переход с изменением размера (Size Transition)

import 'package:flutter/material.dart';
class SizeRoute extends PageRouteBuilder {
  final Widget page;
  SizeRoute({this.page})
      : super(
          pageBuilder: (
            BuildContext context,
            Animation<double> animation,
            Animation<double> secondaryAnimation,
          ) =>
              page,
          transitionsBuilder: (
            BuildContext context,
            Animation<double> animation,
            Animation<double> secondaryAnimation,
            Widget child,
          ) =>
              Align(
                child: SizeTransition(
                  sizeFactor: animation,
                  child: child,
                ),
              ),
        );
}

В результате…

Постепенный переход (Fade Transition)

import 'package:flutter/material.dart';
class FadeRoute extends PageRouteBuilder {
  final Widget page;
  FadeRoute({this.page})
      : super(
          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,
              ),
        );
}

В результате…

Здорово! Мы видели все основные переходы.

Теперь давайте сделаем что-нибудь более продвинутое. Что если мы хотим анимировать оба маршрута. Маршрут входа (новая страница) и маршрут выхода (старая страница). Мы можем использовать анимации переноса в стек и применять их к обоим маршрутам. Одним из примеров может быть слайд-смещение по новому и старому маршрутам. Это моя любимая анимация перехода ❤️. Давайте посмотрим, как это сделать.

import 'package:flutter/material.dart';
class EnterExitRoute extends PageRouteBuilder {
  final Widget enterPage;
  final Widget exitPage;
  EnterExitRoute({this.exitPage, this.enterPage})
      : super(
          pageBuilder: (
            BuildContext context,
            Animation<double> animation,
            Animation<double> secondaryAnimation,
          ) =>
              enterPage,
          transitionsBuilder: (
            BuildContext context,
            Animation<double> animation,
            Animation<double> secondaryAnimation,
            Widget child,
          ) =>
              Stack(
                children: <Widget>[
                  SlideTransition(
                    position: new Tween<Offset>(
                      begin: const Offset(0.0, 0.0),
                      end: const Offset(-1.0, 0.0),
                    ).animate(animation),
                    child: exitPage,
                  ),
                  SlideTransition(
                    position: new Tween<Offset>(
                      begin: const Offset(1.0, 0.0),
                      end: Offset.zero,
                    ).animate(animation),
                    child: enterPage,
                  )
                ],
              ),
        );
}

И используйте это так.

Navigator.push(context,
    EnterExitRoute(exitPage: this, enterPage: Screen2()))

И в результате…

Мы также можем объединить несколько переходов, чтобы создать нечто удивительное, например, масштабирование и вращение одновременно.

Сначала используется ScaleTransition (масштабирование), далее - RotationTransition (вращение), и потом, страница.

import 'package:flutter/material.dart';
class ScaleRotateRoute extends PageRouteBuilder {
  final Widget page;
  ScaleRotateRoute({this.page})
      : super(
          pageBuilder: (
            BuildContext context,
            Animation<double> animation,
            Animation<double> secondaryAnimation,
          ) =>
              page,
          transitionDuration: Duration(seconds: 1),
          transitionsBuilder: (
            BuildContext context,
            Animation<double> animation,
            Animation<double> secondaryAnimation,
            Widget child,
          ) =>
              ScaleTransition(
                scale: Tween<double>(
                  begin: 0.0,
                  end: 1.0,
                ).animate(
                  CurvedAnimation(
                    parent: animation,
                    curve: Curves.fastOutSlowIn,
                  ),
                ),
                child: RotationTransition(
                  turns: Tween<double>(
                    begin: 0.0,
                    end: 1.0,
                  ).animate(
                    CurvedAnimation(
                      parent: animation,
                      curve: Curves.linear,
                    ),
                  ),
                  child: child,
                ),
              ),
        );
}

И в результате:

Отличная работа, ребята! Это все, что вам нужно знать об анимации маршрута перехода в Flutter. Попробуйте сделать некоторые комбинации с переходами и сделайте что-нибудь великое. Если вы сделаете что-то великое, не забудьте поделиться этим со мной. Весь исходный код здесь на GitHub repo.


Узнать подробнее о курсе «Flutter Mobile Developer».

Записаться на открытый онлайн-урок по теме «Графика во Flutter».