Flutter入門進階之旅(十三)Flutter 路由

謝棟發表於2019-04-15

Flutter路由介紹

跟Web頁或者原生APP一樣,我們在使用Flutter 開發APP時也會涉及到多頁面之間的跳轉、引數傳遞、引數回傳等業務,Flutter路由能滿足上述我們提到的所有業務型別,此外我們也可以結合Flutter動畫給路由跳頁時新增個性化的跳頁動畫操作,我會在後續Flutter動畫章節中具體講解。通過本節專題,讀者不僅僅可以自己動手做一些簡單的UI,還能利用Fluttter 路由結合之前的課程分享做一些簡單的多頁面Flutter App。

本期課程目標
  • 瞭解並掌握Flutter路由的簡單使用
  • 掌握Flutter動態路由跟靜態路由的區別
  • 掌握Flutter路由在頁面間的引數傳遞以及回傳流程
  • 藉助路由結合之前的課程做一些簡單的多頁面Flutter APP

關於靜態路由跟動態路由

在Flutter中路由分為靜態路由動態路由兩種:Flutter中所謂的靜態路由指的是需要提前把各個需要跳轉的頁面路徑註冊在routes: <String, WidgetBuilder> {}中,且靜態路由不支援向下一個頁面傳遞引數,但是可以接收下一個頁面的返回值。 動態路由使用就相對來說比較靈活一點,動態路由同樣支援向下一個頁面傳遞引數,而且在使用時不需要我們提前規劃好頁面路徑,只需要在具體跳頁邏輯中自己去構造MaterialPageRoute物件來完成頁面跳轉,或者用PageRouterBuilder來自定義路由跳轉時的動畫,關於路由跳轉動畫我會在Flutter動畫章節中具體講解,當然動態路由同樣也支援頁面引數回傳。

路由場景分類

1.靜態路由跳頁

場景一:點選A頁面中的按鈕跳轉到B頁,不涉及到資料傳遞以及回傳

效果圖

靜態路由跳頁
靜態路由使用時要求我們在MaterialApp中的routes中提前註冊路由

new MaterialApp(
      home: new FlutterDemo(),
      routes: <String, WidgetBuilder>{
        'router/new_page': (_) => new StaticNavigatorPage()
      }));
      
複製程式碼

A頁面程式碼

import 'package:flutter/material.dart';
import 'package:flutter_app/pages/simpleWidget/navigator/StaticNavigatorPage.dart';

void main() {
  runApp(new MaterialApp(
      home: new FlutterDemo(),
      routes: <String, WidgetBuilder>{
        'router/new_page': (_) => new StaticNavigatorPage()
      }));
}

class FlutterDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text("Flutter進階之旅"),
      ),
      body: new Center(
          child: new RaisedButton(
              child: new Text("靜態路由跳頁"),
              onPressed: () {
                Navigator.of(context)
                    .pushNamed('router/new_page'); //這裡一定要保證跳頁的路由路徑跟上面註冊的路徑一致
              })),
    );
  }
}
複製程式碼

B頁面程式碼

import 'package:flutter/material.dart';

class StaticNavigatorPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text("靜態路由頁"),
      ),
      floatingActionButton: new FloatingActionButton(
        onPressed: () {
          Navigator.of(context).pop();
        },
        child: new Text("返回"),
      ),
      body: new Center(
        child: Text("靜態路由可以傳入一個routes引數來定義路由。但是這裡定義的路由是靜態的,"
            "它不可以向下一個頁面傳遞引數,利用push到一個新頁面,pushNamed方法是有一個Future的返回值的"
            ",所以靜態路由也是可以接收下一個頁面的返回值的。但是不能向下一個頁面傳遞引數"),
      ),
    );
  }
}
複製程式碼

上述藉助路由跳頁過程中我們注意到,大概分以下幾步: 1.註冊路由且保證路由的唯一性 2.跳頁時使用Navigator.of(context).pushNamed('路由地址'); 3.使用Navigator.of(context).pop();結束當前頁

2.靜態路由跳頁接收下一頁的返回值

場景二:點選A頁面上的按鈕跳頁到B頁面,在B頁面銷燬後A頁面接收到B頁面回傳回來的值並且顯示在AlertDialog

效果圖

靜態路由回傳資料
A頁面程式碼: 使用Navigator push一個新頁面,pushNamed方法是有一個Future的返回值的,在then回撥中監聽並接收新頁面回傳回來的資料,並且藉助showDialog顯示在Dialog

import 'package:flutter/material.dart';
import 'package:flutter_app/pages/simpleWidget/navigator/StaticNavigatorPageWithParams.dart';

void main() {
  runApp(
      new MaterialApp(home: new FlutterDemo(), routes: <String, WidgetBuilder>{
    'router/new_page_with_callback': (_) => new StaticNavigatorPageWithResult()
  }));
}

class FlutterDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text("Flutter進階之旅"),
      ),
      body: new Center(
          child: new RaisedButton(
              child: new Text("靜態路由接收下一頁返回值"),
              onPressed: () {
                Navigator.of(context)
                    .pushNamed('router/new_page_with_callback')
                    .then((value) {
                  showDialog(
                      context: context,
                      child: new AlertDialog(
                        content: new Text(value),  
                      ));
                });
              })),
    );
  }
}
複製程式碼

B頁面程式碼:

從效果圖中可以看到,當我點選B頁面中間的按鈕時會把資料回傳給上一頁,但是直接點選導航欄左上角的返回按鈕回到A頁面時並不會把資料傳遞給上一個頁面,這裡是因為我在B頁面的按鈕上pop頁面出棧的時候把引數放進裡面作為了引數傳遞,pop()可接收一個Object物件作為引數傳遞

Navigator.of(context).pop(T extends Object);
複製程式碼

這就告訴我們當我們需要給上一個頁面回傳資料的時候可直接藉助pop傳遞Navigator.of(context).pop("頁面結束後返回的資料");,不需要傳值的時候直接返回空物件Navigator.of(context).pop()即可。

import 'package:flutter/material.dart';

class StaticNavigatorPageWithResult extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text("靜態路由帶返回引數"),
      ),
      body: new Center(
        child: new OutlineButton(
          onPressed: () {
            Navigator.of(context).pop("頁面結束後返回的資料");
          },
          child: Text("點我返回上個頁面結束後返回的資料"),
        ),
      ),
    );
  }
}

複製程式碼

3.動態路由跳頁

文章的開頭我們提到藉助動態路由可以向下一個頁面傳遞引數,同樣也可以接收新頁面回傳回來的資料。下面我模擬兩個使用動態路由的場景,既然動態路由可以傳值那就肯定可以不傳值跳頁,我就不模擬動態路由不傳值跳頁的例子了,讀者藉助靜態路由的樣例自行測試即可,我們主要講解一下藉助動態路由傳值的例子。

場景三:點選A頁面中的按鈕,把使用者名稱跟密碼傳遞給下一個頁面B頁面,B頁面處理完接收到的資料後把結果回傳給A頁面,A頁面中把從B頁面回傳回來的資料顯示在Dialog上。

模擬效果圖

動態路由傳遞引數
使用動態路由時我們不再需要像靜態路由那樣在MaterialApp中的router中提前註冊路由路徑,只需要在使用Navigator.push傳入MaterialPageRoute物件即可

 Navigator.push(
    context,
    new MaterialPageRoute(
        //_代表引數為空
        builder: (_) => new DynamicNaviattionPage(
              username: "xiedong",
              password: "123456",
            )));
複製程式碼

A頁面程式碼:

import 'package:flutter/material.dart';
import 'package:flutter_app/pages/simpleWidget/navigator/DynamicNavigationPage.dart';

void main() {
  runApp(new MaterialApp(home: new FlutterDemo()));
}

class FlutterDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
        appBar: new AppBar(
          title: new Text("Flutter進階之旅"),
        ),
        body: new Center(
            child: new RaisedButton(
          onPressed: () {
            Navigator.push(
                context,
                new MaterialPageRoute(
                    //_代表引數為空
                    builder: (_) => new DynamicNaviattionPage(
                          username: "xiedong",
                          password: "123456",
                        ))).then((value) {
              showDialog(
                  context: context,
                  child: new AlertDialog(
                    content: new Text(value),
                  ));
            });
          },
          child: new Text("動態路由傳參"),
        )));
  }
}
複製程式碼

B頁面程式碼:

import 'package:flutter/material.dart';

class DynamicNaviattionPage extends StatelessWidget {
  var username;
  var password;

  DynamicNaviattionPage({Key key, this.username, this.password})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text("動態路由"),
      ),
      body: new Center(
        child: new Column(
          children: <Widget>[
            new MaterialButton(
              onPressed: () {
                Navigator.pop(context, "未查詢到改該使用者資訊");
              },
              child: new Text("點我返回"),
              color: Colors.lightGreen,
            ),
            new Text("上頁傳遞過來的username   $username"),
            new Text("上頁傳遞過來的password   $password"),
          ],
        ),
      ),
    );
  }
}
複製程式碼

關於路由重點總結

  • Flutter路由分為靜態路由跟動態路由,靜態路由不支援向下一個頁面傳遞引數,動態路由可傳遞
  • 靜態路由使用時需要提前註冊宣告頁面路徑,
  • 動態路由可以直接在使用時構造路由物件,不需要提前註冊路徑。
  • 兩種型別都支援接收下一頁面回傳回來的值

相關文章