flutter中的路由過場動畫 PageTransitionsTheme

CaiJingLong發表於2020-02-24

過場動畫

過場動畫也就是切換路由時的動畫

這個東西有幾種方案可以做

  1. 繼承 PageRoute來做, 複寫 5 個抽象方法, 並抽象buildTransitions
  2. 繼承已有的系統類, 比如 MaterialPageRoute 或者 CupertinoPageRoute
  3. 一勞永逸的方案, 使用PageTransitionsTheme類結合 MaterialApp 的 theme 的pageTransitionsTheme屬性

前兩種目前網路上也有一些人做了分享, 但第三種好像很少有人使用, 我這裡就來說一下PageTransitionsTheme的用法

這東西有如下的好處:

  1. 設定一次, 你所有的MaterialPageRoute都可以生效
  2. 對於命名路由, 也就是pushNamed體系的也有效

先分析下原始碼

為啥分析原始碼? 因為如果上來就用顯得不高階

先找一個大家都知道的切入點, 一般的過場動畫都是用的 Navigator.push 方法來實現的

image

看看方法裡的實現, 會發現很多常見的東西, 比如, 每一個 Route 都有自己的 OverlayEntry

然後會有一個 install 方法

image

而實際呼叫中, 這個 Overlay 會被插入到 Overlay 棧內, 從而在介面上顯示

image

image

image

image

經過這一串的呼叫, 就把 Navigator push 和 Route 關聯到了一起, 那麼 theme 是怎麼和 Route 關聯起來的呢, 我們進入 MaterialPageRoute 看一下

image

我們看到, 這裡是從 Theme 中找到 pageTransitionsTheme, 然後呼叫 pageTransitionsTheme 的 buildTransitions 方法來完成構建, 所以這就是我們可以在 theme 中一次修改, 多處生效的主因了

如何使用

前面檢視到了原始碼是如何關聯到 pageTransitionsTheme 屬性的, 我們接著就是該自定義的時候了

修改自己的 MyApp, 修改pageTransitionsTheme屬性


class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        pageTransitionsTheme: PageTransitionsTheme(
          builders: <TargetPlatform, PageTransitionsBuilder>{
            TargetPlatform.iOS: createTransition(),
            TargetPlatform.android: createTransition(),
          },
        ),
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

複製程式碼

使用系統提供的一些動畫


PageTransitionsBuilder createTransition() {
  return FadeUpwardsPageTransitionsBuilder();
}

複製程式碼

效果如下:

image

根據註釋, sdk 中有如下幾種動畫

image

其中FadeUpwardsPageTransitionsBuilder對應安卓預設的, PageTransitionsBuilder自然是對應的 iOS

ZoomPageTransitionsBuilder:

image

OpenUpwardsPageTransitionsBuilder:

image

自定義

除了已有的, 我們還可以自定義動畫, 可以配合 animation元件來完成酷炫的動畫效果, 具體的可以檢視官網動畫部分介紹

自定義 MyPageTransitionsBuilder

import 'package:flutter/material.dart';

PageTransitionsBuilder createTransition() {
  // return FadeUpwardsPageTransitionsBuilder();
  // return OpenUpwardsPageTransitionsBuilder();
  // return ZoomPageTransitionsBuilder();
  return MyPageTransitionsBuilder();
}

class MyPageTransitionsBuilder extends PageTransitionsBuilder {
  @override
  Widget buildTransitions<T>(
      PageRoute<T> route,
      BuildContext context,
      Animation<double> animation,
      Animation<double> secondaryAnimation,
      Widget child) {
    return ScaleTransition(
      scale: animation,
      child: RotationTransition(
        turns: animation,
        child: child,
      ),
    );
  }
}
複製程式碼

效果如下

image

後記

倉庫地址

有問題請在本人部落格下留言(github 登陸即可)

相關文章