Flutter Navigation(導航)

在 Flutter 里實現(xiàn)頁面的導航需要使用兩個類:NavigatorRoute。Navigator 負責頁面的棧結構處理,Route 復雜頁面的路徑處理。

在 Flutter 里導航器使用棧的結構管理頁面,當需要添加一個頁面時,使用入棧的方式。當需要退出一個頁面時,使用出棧的方式。也可以不入棧而是直接替換當前頁面。

路由表

移動應用程序通常管理大量的路由,通過名稱來引用它們通常是最容易的。

簡單的做法是在 runApp 里,就定義好所有的路由,這樣可以做集中式管理,也是非常建議的做法。

一個 MaterialApp 是最簡單的設置方式,MaterialApp 的 home 成為導航器堆棧底部的路由。要在堆棧上推送(push)一個新路由,可以創(chuàng)建一個具有構建器功能的MaterialPageRoute 實例。

void main() {
    runApp(new MaterialApp(
        home: new MyAppHome(),
        // 路由
        routes: <String, WidgetBuilder> {
            '/a': (BuildContext context) => new MyPage(title: 'page A'),
            '/b': (BuildContext context) => new MyPage(title: 'page B'),
            '/c': (BuildContext context) => new MyPage(title: 'page C'),
        },
    ));
}

當需要路由切換的時候,可以這樣處理。

Navigator.pushNamed(context, '/b');

傳遞數(shù)據(jù)

很多時候在切換路由時需要傳遞一些數(shù)據(jù),比如 id 之類的,那么應該怎么做?

在使用動態(tài)路由時,可以通過閉包環(huán)境來傳遞數(shù)據(jù)。

String id = 'abc';                                              // <--- id

Navigator.push(context, new MaterialPageRoute<void> (
    // 新的頁面
    builder: (BuildContext context) {
        return new Scaffold(
            body: new Center(
                child: new FlatButton(
                    child: new Text('POP'),
                    onPressed: () {
                        print(this.id);                         // <--- id
                        Navigator.pop(context);
                    },
                ),
            ),
        );
    },
));

在使用路由表的時候,只能提供全局變量來傳遞信息。

var id = 'abc';

void main() {
    runApp(new MaterialApp(
        home: new MyAppHome(),
        // 路由
        routes: <String, WidgetBuilder> {
            '/a': (BuildContext context) => new MyPage(id: id),
        },
    ));
}

入棧一個頁面

當需要入棧一個頁面時,使用 Navigator.push 函數(shù),這個函數(shù)接受一個上下文和新的頁面結構。第二個參數(shù)是一個路由器 MaterialPageRoute

// 在某個點擊事件里
Navigator.push(context, new MaterialPageRoute<void> (
    // 新的頁面
    builder: (BuildContext context) {
        return new Scaffold(
            appBar: new AppBar(title: new Text('My Page')),
            body: new Center(
                child: new FlatButton(
                    child: new Text('POP'),
                    onPressed: () {
                        Navigator.pop(context);
                    },
                ),
            ),
        );
    },
));

出棧一個頁面

當需要出棧一個頁面時,使用 Navigator.pop 函數(shù),這個函數(shù)接受一個上下文。

new FlatButton(
    child: new Text('POP'),
    onPressed: () {
        Navigator.pop(context);
    },
),

接受返回值

實際上 pushNamed 是一個異步函數(shù),它返回一個 Future,在使用 Navigator.pop 的時候,第二個參數(shù)就是返回的值。

Navigator.pop(context, 'abc');

Navigator.pushNamed(context, '/router/second').then((value) {
    print(value);   // --> abc
});

導航切換動畫

默認的導航切換動畫,在 Android 上是一個從底端到頂端的彈出過程,在 iOS 上是一個從右邊到左邊的平移過程。

為了統(tǒng)一,可以通過自定義一個路由,包括路由模態(tài)屏障的顏色和行為以及路由其他方面的動畫轉換。

// 動畫效果,要把它放在外面去,并且是 static 的。
static SlideTransition createTransition(Animation<double> animation, Widget child) {
    return new SlideTransition(
        // 從右到左
        position: new Tween<Offset>(
            begin: const Offset(1.0, 0.0),
            end: const Offset(0.0, 0.0),
        ).animate(animation),
        child: child,
    );
}

Navigator.of(context).push(
    new PageRouteBuilder(
        pageBuilder: (
            BuildContext context,
            Animation<double> animation,
            Animation<double> secondaryAnimation,
        ) {
        // 目標頁
        return new PageView();
    },
    transitionsBuilder: (               // --> 固定寫法
        BuildContext context,
        Animation<double> animation,
        Animation<double> secondaryAnimation,
        Widget child,
    ) => HomePageState.SlideTransition(animation, child),
));

實際上,默認在 Android 上的效果是:

// 從下到上
position: new Tween<Offset>(
    begin: const Offset(0.0, 1.0), // (x, y)
    end: const Offset(0.0, 0.0),
).animate(animation),

這里只是把 x 與 y 對換就變成了平移。

得出幾個不同的方向動畫。

// 從上到下
position: new Tween<Offset>(
    begin: const Offset(0.0, -1.0), // (x, y)
    end: const Offset(0.0, 0.0),
).animate(animation),

// 從左到右
position: new Tween<Offset>(
    begin: const Offset(-1.0, 0.0), // (x, y)
    end: const Offset(0.0, 0.0),
).animate(animation),

神奇的是 begin 可以使用對角移動的方式,也就是 (1.0, 1.0)、(-1.0, -1.0)

除了平移之外,還可以定義一些旋轉的動畫。

static FadeTransition createFadeTransition(Animation<double> animation, Widget child) {
    return new FadeTransition(
        opacity: animation,
        child: new RotationTransition(
            turns: new Tween<double>(
                begin: 0.8,
                end: 1.0
            ).animate(animation),
            child: child,
        ),
    );
}

當 begin 與 end 都為 1.0 時,F(xiàn)adeTransition 是一個透明漸變過程。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 用兩張圖告訴你,為什么你的 App 會卡頓? - Android - 掘金 Cover 有什么料? 從這篇文章中你...
    hw1212閱讀 12,953評論 2 59
  • 署假,我和國寶帶著5歲的楊楊回到了老家鄉(xiāng)下。 孩子的爺爺奶奶非常高興,他們從接到楊楊回家起,嘴巴就沒有合攏過,眼睛...
    詩意的云閱讀 228評論 0 1
  • 愛能創(chuàng)造奇跡 --觀《奇跡男孩》有感 之前朋友強烈推薦《Wonder》這本書,朋友跟我說起這本書創(chuàng)...
    美好彤行閱讀 241評論 0 0
  • 原文:打諢隨時之妙法,休嫌終日昏昏;精明當事之禍機,卻恨一生了了,藏不得是拙,露不得是丑。 評:露丑賣乖、假裝糊涂...
    簡溪_向日葵閱讀 1,209評論 0 0