Flutter早知道 - Named Router可以傳參了!

rojer95發表於2019-02-25

本文中涉及部分非Flutter的stable版本(2019年2月25日 為止),您可查閱Flutter相關文件檢視新功能是否同步的stable分支或者切換其他分支(如master)中體驗

引言

在我們使用Flutter開發App時,路由是必須用到的。

Flutter提供了兩種方式進行路由,分別是 Navigator.push() () 以及 Navigator.pushNamed() ()。

對於這兩種方式各有各的優點與缺點:

  1. Navigator.push()
  • 優點:動態、自由度大,可以以不同的動畫方式跳轉到新頁面,且可以傳遞引數到新的頁面。
  • 缺點:會造成程式碼冗餘,而且不便於程式碼維護。(當然你可以將其進行封裝 這裡不討論這一點)
  1. Navigator.pushNamed()
  • 優點:一句話就能實現頁面的跳轉與目前大多數框架的方式相似。
  • 缺點:不能傳遞引數!不能傳遞引數!不能傳遞引數!

選擇

在實際開發運用中,我們也是更加傾向於Named路由方式。

但是唯一不足之處就是它不支援傳遞引數,這一點實在是令人抓狂。

其實在Flutter的Issues中16年就有人提出這個問題,但是這個Issue一直到今年才有PR被提交(目前為止這個功能僅僅被合併進master分支並沒有同步到bate或者stable)

上手體驗

  1. 首先我們要切到master分支下

執行 flutter channel master 然後再執行命令flutter upgrade保證你處於最新的版本。即可切換到master分支下

  1. 建立一個Flutter專案
  2. 這裡我們在main.dart中略作修改
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatelessWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(this.title),
      ),
      body: Center(
        child: GestureDetector(
          onTap: (){
            // TODO
          },
          child: Text("go next page with params"),
        ),
      ),
    );
  }
}


複製程式碼
  1. 新增第二個頁面page.dart
import 'package:flutter/material.dart';

class Page extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return Material(
      child: Center(
        child: Text("hi this is next page"),
      ),
    );
  }
}
複製程式碼
  1. 新增路由並跳轉同時傳遞引數 main.dart
import 'package:flutter/material.dart';
// 引入新頁面
import 'page.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      // 處理Named頁面跳轉 傳遞引數
      onGenerateRoute: (RouteSettings setting) {
        if(setting.name == '/page') {
          return MaterialPageRoute(builder: (context) => Page(id: setting.arguments['id']));
        }
      },
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatelessWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(this.title),
      ),
      body: Center(
        child: GestureDetector(
          onTap: (){
            // 進行Named頁面跳轉 傳遞引數
            Navigator.pushNamed(context, '/page', arguments: { "id": 1} );
          },
          child: Text("go next page with params"),
        ),
      ),
    );
  }
}


複製程式碼
  1. 頁面接受引數 page.dart
import 'package:flutter/material.dart';

class Page extends StatelessWidget{
  Page({this.id});
  final int id;

  @override
  Widget build(BuildContext context) {
    return Material(
      child: Center(
        child: Text("hi this is next page, id is $id"),
      ),
    );
  }
}
複製程式碼

效果

Flutter早知道 - Named Router可以傳參了!

優化

這裡我們還是要在onGenerateRoute處理我們的Named跳轉,我們在對他進行優化一下。

(目前沒辦法在MaterialApp的routes進行處理,原因可見原始碼()())

原始碼一處:呼叫widget.pageRouteBuilder並傳入settings(argumentssettings中)

原始碼二處:pageRouteBuilder被寫死為構建一個MaterialPageRoute,而MaterialPageRoute中並沒有對settings進行傳遞

所以我們只能自己在onGenerateRoute中進行處理。(希望官網也能繼續優化,emmmm拭目以待)

/**
 *   main.dart
 */
import 'package:flutter/material.dart';
// 引入新頁面
import 'page.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // 定義路由資訊
  final Map<String, Function> routes = {
    '/page': (context, {arguments}) => Page(arguments: arguments)
  };

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      // 處理Named頁面跳轉 傳遞引數
      onGenerateRoute: (RouteSettings settings) {
        // 統一處理
        final String name = settings.name;
        final Function pageContentBuilder = this.routes[name];
        if (pageContentBuilder != null) {
          final Route route = MaterialPageRoute(
              builder: (context) =>
                  pageContentBuilder(context, arguments: settings.arguments));
          return route;
        }
      },
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatelessWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(this.title),
      ),
      body: Center(
        child: GestureDetector(
          onTap: () {
            // 進行Named頁面跳轉 傳遞引數
            Navigator.pushNamed(context, '/page', arguments: {'id': 123});
          },
          child: Text("go next page with params"),
        ),
      ),
    );
  }
}


/**
 *   page.dart
 */

import 'package:flutter/material.dart';

class Page extends StatelessWidget{
  Page({this.arguments});
  final Map arguments;

  @override
  Widget build(BuildContext context) {
    return Material(
      child: Center(
        child: Text("hi this is next page, id is ${arguments != null ? arguments['id'] : '0'}"),
      ),
    );
  }
}

複製程式碼

相關程式碼

flutter_new_feature

相關文章