1. 程式人生 > 實用技巧 >Flutter 如何在切換頁面的時候,把引數傳到下一個頁面?

Flutter 如何在切換頁面的時候,把引數傳到下一個頁面?

講解Flutter 路由傳遞,這是一個大的概述圖。

當 app 的頁面變多的時候,就需要考慮頁面傳值的問題,在第一個頁面如何把資料傳遞到 另外一個頁面?最最基本的方法是在開啟新頁面,傳遞引數過去。但當 app 變得很大或者功能變多,你會發現傳值是一件費勁的事情。例如前期設計的時候,只需要一個引數,但後面發現業務可能需要三個引數,如果再追加兩個引數也不是不可以,就是不太優雅,而且可能要修改很多地方。

跳轉到一個介面

先簡單解釋一下,下面會使用到, App 啟動一個主介面,然後點選中間按鈕,會開啟第二個介面。點選第二個介面的右上角,會返回到之前的介面。具體程式碼如下:

import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';

class Test extends StatefulWidget {
  @override
  _TestState createState() => _TestState();
}

class _TestState extends State<Test> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('路由'),
      ),
      body: Center(
        child: FloatingActionButton(
          shape: BeveledRectangleBorder(),
          child: Text('按鈕'),
          onPressed: () {
            //使用路由開啟 第二個介面
            Navigator.push(
                context, MaterialPageRoute(builder: (context) => TwoPage()));
          },
        ),
      ),
    );
  }
}

class TwoPage extends StatefulWidget {
  @override
  _TwoPageState createState() => _TwoPageState();
}

class _TwoPageState extends State<TwoPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('第二頁'),
      ),
      body: Column(
        children: <Widget>[
          SizedBox(height: 100),
          Text('傳遞過來的值:\n'),
          SizedBox(height: 100),
          Center(
            child: FloatingActionButton(
              shape: BeveledRectangleBorder(),
              child: Text('返回'),
              onPressed: () {
                // 返回到上一個介面
                Navigator.pop(context);
              },
            ),
          )
        ],
      ),
    );
  }
}

使用構造傳參

使用構造引數把引數傳遞過去,在 TwoPage 中接受引數可直接用 widget.x , x 表示 _TwoPageState 傳遞過來的 widget 中包含值。

class _TestState extends State<Test> {
        ...
    onPressed: () {
        String name = "Wang";
        String age = "99";

        Navigator.push(context, MaterialPageRoute(builder: (context) => TwoPage(name, age)));
      },
    ...
}

class TwoPage extends StatefulWidget {
  String name;
  String age;

  TwoPage(this.name, this.age);
    ...
    Text('傳遞過來的值:\n ${widget.name}_${widget.age}'),
    ...
}

List(陣列)傳參

這裡演示了 使用構造傳遞一個 List 型別的數, 使用 widget.data 的列表指令碼獲取資料。

class _TestState extends State<Test> {
        ...

        dynamic data = ['name1', 'age'];
    Navigator.push(context, MaterialPageRoute(builder: (context) => TwoPage(data)));

    ...
}

class TwoPage extends StatefulWidget {
    ...
    dynamic data;
    TwoPage(this.data);
    ...
}

class _TwoPageState extends State<TwoPage> {
    ...
    Text('傳遞過來的值:\n ${widget.data[0]}_${widget.data[1]}'),
    ...
}

Map 傳參

這裡演示了 使用構造傳遞一個 map 型別的資料。

class _TestState extends State<Test> {
        ...

        dynamic map = {
              'name': "Wang_Map",
              'age': "99",
            };
    Navigator.push(context, MaterialPageRoute(builder: (context) => TwoPage(map)));

    ...
}

class TwoPage extends StatefulWidget {
    ...
    dynamic map;
    TwoPage(this.map);
    ...
}

class _TwoPageState extends State<TwoPage> {
    ...
    Text('傳遞過來的值:\n ${widget.map["name"]}_${widget.map["age"]}'),
    ...
}

廣州品牌設計公司https://www.houdianzi.com

使用帶名字的路由傳參

很多時候我們專案比較大,為了統一管理,會使用帶名字的路由概念,下面的路由字串常量可以寫成變數,這樣後期不管怎麼修改裡面的值,依賴的地方都是不需要修改的。

傳遞一個引數

這裡傳遞了一個 name 值,演示了一下 使用帶名字的路由傳遞值。

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      initialRoute: "/",
      routes: {
        "/": (context) => OnePage(),
        "/TwoPage": (context) => TwoPage(),
      },
    );
  }
}


class OnePage extends StatefulWidget {
  @override
  _OnePageState createState() => _OnePageState();
}

class _OnePageState extends State<OnePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('路由頁面'),
      ),
      body: Center(
        child: FloatingActionButton(
          shape: BeveledRectangleBorder(),
          child: Text('按鈕'),
          onPressed: () {
            String name = "Wang";

            Navigator.pushNamed(context, '/TwoPage', arguments: name);

          },
        ),
      ),
    );
  }
}

class TwoPage extends StatefulWidget {

  @override
  _TwoPageState createState() => _TwoPageState();
}

class _TwoPageState extends State<TwoPage> {
  @override
  Widget build(BuildContext context) {
    dynamic name = ModalRoute.of(context).settings.arguments;

    return Scaffold(
      appBar: AppBar(
        title: Text('第二頁'),
      ),
      body: Column(
        children: <Widget>[
          SizedBox(height: 100),
          Text('傳遞過來的值:\n $name'),
          SizedBox(height: 100),
          Center(
            child: FloatingActionButton(
              shape: BeveledRectangleBorder(),
              child: Text('返回'),
              onPressed: () {
                Navigator.pop(context);
              },
            ),
          )
        ],
      ),
    );
  }
}

傳遞 List(陣列)

我們這裡傳遞的是 List,可以根據角標進行獲取對應值,前提是對值瞭解,一般這裡會傳遞一個列表展示或者一個 List 包含多個不同的值,方便從上一次獲取。

class _OnePageState extends State<OnePage> {
    ...
    onPressed: () {
        dynamic listData = ['name1', 'age'];
        Navigator.pushNamed(context, '/TwoPage', arguments: listData);
    }
    ...
}

class _TwoPageState extends State<TwoPage> {
  @override
  Widget build(BuildContext context) {
    dynamic listData = ModalRoute.of(context).settings.arguments;
    String name = listData[0];
    String age = listData[1];

        ...
        SizedBox(height: 100),
        Text('傳遞過來的值:\n $name _ $age'),
        SizedBox(height: 100),
        ...
  }
}

傳遞 Map

因為我們傳遞的是 map,所以在接收的時候需要做一次判斷,用 is 判斷,預防外界傳入其他型別,造成我們程式紅屏。這裡可以從上一次獲取多個不同的引數,使用不同名稱獲取,這裡最好對接收到的值做判斷,非空校驗等。

class _OnePageState extends State<OnePage> {
    ...
    onPressed: () {
        dynamic listData = ['name1', 'age'];
        Navigator.pushNamed(context, '/TwoPage', arguments: listData);
    }
    ...
}

class _TwoPageState extends State<TwoPage> {
  @override
  Widget build(BuildContext context) {
    String name;
    String age;

    dynamic mapData = ModalRoute.of(context).settings.arguments;
    // 可以做一次校驗資料安全,防止型別不匹配
    if (mapData is Map) {
      Map data = mapData;
      name = data['name'];
      age = data['age'];
    }

        ...
        SizedBox(height: 100),
        Text('傳遞過來的值:\n $name _ $age'),
        SizedBox(height: 100),
        ...
  }
}

普通路由帶參

和帶路由名字的方式基本一樣,不過寫的方式略有不同,需要把引數放入 settings 後面。

Navigator.of(context).push(new MaterialPageRoute(
  builder: (context) {
       return NewRouteWidget(); //寫上要跳轉到的頁面
  },
   settings:
       RouteSettings(arguments: {'name': 'postbird'}), // 傳參
   fullscreenDialog: true));

帶引數從二級頁面返回上一級

返回上一級:

Navigator.pop(context);

帶引數返回上一級:

Navigator.pop(context, '返回的文字資料');

帶型別的引數返回:

Navigator.pop<Map>(context, mapData);
Navigator.pop<List>(context, listData);
Navigator.pop<T>(context, data);

在上一級接受返回的值:

這裡使用 then 接受,也可以使用 await, 只是這種方法更容易理解和接受,邏輯更強,程式碼簡潔。

Navigator.pushNamed(context, '/TwoPage', arguments: mapData)
      .then((dynamic data) {
      print("返回的值是:$data");
});