[譯] 關於 Flutter 頁面路由過渡動畫,你所需要知道的一切

Yuqi發表於2019-05-27

關於 Flutter 頁面路由過渡動畫,你所需要知道的一切

[譯] 關於 Flutter 頁面路由過渡動畫,你所需要知道的一切

在使用 Flutter 的時候,我們都知道從一個路由跳轉到另一個這件事非常簡單。我們只需要做 push 和 pop 的操作即可。

push 操作:

Navigator.push(
    context,
    MaterialPageRoute(builder: (context) => SecondRoute()),
  );
複製程式碼

pop 操作:

Navigator.pop(context);
複製程式碼

就這麼簡單。但是這樣做,路由跳轉就是無聊的頁面切換,完全沒有動畫效果 ?

當我們在 Winkl 開始第一次應用動畫效果,我們意識到,頁面跳轉的過渡效果可以讓你的使用者互動介面變得很好看。如果你想要一個像 iOS 上那樣的滑動頁面切換,你可以用 CupertinoPageRoute。只有這個,沒有其他的了。

Navigator.push(
    context, CupertinoPageRoute(builder: (context) => Screen2()))
複製程式碼

但是,對於使用者自定義的過渡效果,Flutter 提供了不同的方案:動畫元件。下面我們一起來看看如何應用它。

我們知道,Navigator.push 接受兩個引數 (BuildContext context, Route route)。我們可以使用一些過渡動畫來建立自定義的頁面路由跳轉。我們先從一些簡單的例子開始,比如滑動過渡。

滑動過渡

首先,我們要擴充類 PageRouteBuilder,然後定義 transitionsBuilder,它將返回滑動過渡元件。這個滑動過渡元件將使用型別 Animation 的位置資訊,我們將會使用 Tween 來給出動畫開始和結束的偏移量。

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()))
複製程式碼

程式碼執行的效果是...

[譯] 關於 Flutter 頁面路由過渡動畫,你所需要知道的一切

程式碼非常簡單的對吧?你可以通過修改偏移量 offset 來改變滑動過渡的方向。

縮放過渡

縮放過渡會通過改變元件的大小來完成動畫效果。你也可以通過修改 CurvedAnimationcurves 來改變動畫。下面這個例子我使用的是 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,
              ),
        );
}
複製程式碼

程式碼執行的效果是...

[譯] 關於 Flutter 頁面路由過渡動畫,你所需要知道的一切

旋轉過渡

旋轉過渡會以轉動作為元件的動畫。你也可以為你的 PageRouteBuilder 加入 transitionDuration

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,
              ),
        );
}
複製程式碼

程式碼執行的效果是...

[譯] 關於 Flutter 頁面路由過渡動畫,你所需要知道的一切

大小過渡

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,
                ),
              ),
        );
}
複製程式碼

程式碼執行的效果是...

[譯] 關於 Flutter 頁面路由過渡動畫,你所需要知道的一切

漸變過渡

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,
              ),
        );
}
複製程式碼

程式碼執行的效果是...

[譯] 關於 Flutter 頁面路由過渡動畫,你所需要知道的一切

棒棒噠!! 現在我們學習過了所有基礎的過渡效果。


現在我們來實踐一些更高階的。如果在進入頁面和離開頁面這兩個路由跳轉的時候都想要動畫該怎麼做呢?我們可以使用堆疊過渡動畫(stack transition animations),並應用於這兩個路由跳轉上。一個例子就是滑入新頁面,然後劃出舊頁面。這是我最喜歡的過渡動畫了 ❤️。我們來看看程式碼是如何實現的。

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,
                  )
                ],
              ),
        );
}
複製程式碼

然後如下這樣來使用 EnterExitRoute:

Navigator.push(context,
    EnterExitRoute(exitPage: this, enterPage: Screen2()))
複製程式碼

程式碼執行的效果是...

[譯] 關於 Flutter 頁面路由過渡動畫,你所需要知道的一切


我們也可以將多個過渡效果結合在一起,建立出很多神奇的效果,比如同時應用縮放和旋轉。首先,建立 ScaleTransition,它的 child 屬性包括了 RotationTransition,而 RotationTransition 的 child 屬性則是要顯示動畫的頁面。

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 頁面路由過渡動畫,你所需要知道的一切


[譯] 關於 Flutter 頁面路由過渡動畫,你所需要知道的一切

棒極了!這些就是關於 Flutter 頁面路由過渡動畫,你所需要知道的一切。親自試著將不同的過渡效果結合起來,創造出一些很棒的動畫吧,並且別忘了和我分享你的成果。所有程式碼的原始碼可見:GitHub 倉庫


如果你喜歡本篇文章那就請點個贊吧,並且可以在 TwitterGithubLinkedIn 聯絡我。

如果發現譯文存在錯誤或其他需要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可獲得相應獎勵積分。文章開頭的 本文永久連結 即為本文在 GitHub 上的 MarkDown 連結。


掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智慧等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章