Flutter基礎(十二)路由(頁面跳轉)與數據傳遞

本文首發於公衆號「劉望舒」html

ReactNative入門系列
React Native組件
Flutter基礎系列前端

前言

在Android開發中咱們使用Intent來進行頁面跳轉,也稱之爲原生路由,後來出現了一些路由框架,好比ARouter。 在Flutter中進行界面跳轉的就是路由,路由用Route類來進行表示,Navigator是對Route進行管理的Widget。這一篇文章咱們來學習路由和數據傳遞。flutter路由的使用方式主要有兩種,一種是新建路由,一種是註冊路由。java

1.新建路由

建立兩個頁面,第一個頁面有一個按鈕,點擊這個按鈕跳到第二個頁面。先來實現第一個頁面:程序員

class FirstPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("第一頁"),
      ),
      body: Center(
        child: RaisedButton(
          child: Text("跳轉到第二頁"),
          onPressed: () {
            Navigator.push(
                context,
                MaterialPageRoute(
                    builder: (context) => SecondPage(), maintainState: false));
          },
        ),
      ),
    );
  }
}
複製代碼

經過Navigator.push()方法將一個Route對象添加到Navigator管理的Route堆棧中,這裏的Route對象是一個MaterialPageRoute,它自帶頁面切換動畫,而且適配了Android和iOS,若是是Android,頁面進入動畫是向上滑動並淡出,退出是相反的;若是是iOS,頁面進入動畫是從右側滑入,退出一樣是相反的。通常來講使用MaterialPageRoute就夠用了,若是不知足需求,能夠實現自定義Route。 接着來實現第二個頁面,代碼以下所示。json

class SecondPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("第二頁"),
      ),
      body: Center(
        child: RaisedButton(
          child: Text("返回到第二頁"),
          onPressed: () {
            Navigator.pop(context);
          },
        ),
      ),
    );
  }
}
複製代碼

Navigator.pop()方法用於關閉當前頁面,返回上一個頁面,並將當前的Route對象從Navigator管理的Route 堆中移除。 完整的代碼以下所示。網絡

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "Flutter",
      home: FirstPage(),
    );
  }
}

class FirstPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("第一頁"),
      ),
      body: Center(
        child: RaisedButton(
          child: Text("跳轉到第二頁"),
          onPressed: () {
            Navigator.push(
              context,
              MaterialPageRoute(
                builder: (context) => SecondPage(),
                maintainState: false,
              ),
            );
          },
        ),
      ),
    );
  }
}

class SecondPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("第二頁"),
      ),
      body: Center(
        child: RaisedButton(
          child: Text("返回到第二頁"),
          onPressed: () {
            Navigator.pop(context);
          },
        ),
      ),
    );
  }
}

複製代碼

運行程序,效果以下所示。 app

Zc1mCt.png

2.使用註冊路由

若是不少頁面都跳轉到了同一個頁面,每次都要新建路由,那麼會寫不少重複的代碼,使用註冊路由就能夠簡化。框架

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "Flutter",
      initialRoute: '/First',//1
      routes: {
        '/First': (context) => FirstPage(),
        "/Second": (context) => SecondPage()
      },
      home: FirstPage(),
    );
  }
}

class FirstPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("第一頁"),
      ),
      body: Center(
        child: RaisedButton(
          child: Text("跳轉到第二頁"),
          onPressed: () {
            Navigator.pushNamed(context, '/Second');//2
          },
        ),
      ),
    );
  }
}
...
複製代碼

省略了第二頁的代碼,由於沒有什麼變化。改變的是咱們須要定義路由表,路由表的格式爲Map<String, WidgetBuilder> routes; 其中key爲路由名稱,value是builder回調函數,用於生成相應的路由Widget。經過路由名稱入棧新路由時,應用會根據路由名稱在路由表中找到對應的WidgetBuilder回調函數,經過調用該回調函數生成路由widget並返回。 註釋1處用來定義初始路由的頁面,接着註冊路由表,裏面包含了兩個頁面,分別是FirstPage和SecondPage。 註釋2處經過路由名稱來打開SecondPage。less

3.路由間數據傳遞

頁面跳轉的時候常常須要傳遞數據,通常有兩種狀況,一種是頁面跳轉數據傳遞,另外一種是頁面跳轉返回數據,這裏分別來進行介紹。異步

3.1 頁面跳轉數據傳遞

一個頁面跳轉到一個新的頁面數據傳遞的方式主要有如下兩種:

  • 經過 Navigator.push() 或者 Navigator.pushNamed() 方法傳遞數據
  • 經過Widget的構造函數傳遞數據

通常來講會使用第一種方式,下面來進行舉例。

class FirstPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("第一頁"),
      ),
      body: Center(
        child: RaisedButton(
          child: Text("跳轉到第二頁"),
          onPressed: () {
            Navigator.pushNamed(context, '/Second',arguments: CustomArgumnets('Android進階之光'));
          },
        ),
      ),
    );
  }
}
class CustomArgumnets {
  String content;
  PassArgumnets(this.content);
}
複製代碼

咱們經過arguments屬性來傳遞參數,這裏自定義了一個CustomArgumnets,用來傳遞參數。 改寫第一小節SecondPage的代碼用來獲取數據,以下所示。

class SecondPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final CustomArgumnets customArgumnets =ModalRoute.of(context).settings.arguments;
    return Scaffold(
      appBar: AppBar(
        title: Text("第二頁"),
      ),
      body: Center(
        child: Column(
          children: <Widget>[
            Text('第一頁的數據爲:'),
            Text(customArgumnets.content),
            RaisedButton(
              onPressed: () {
                Navigator.pop(context);//1
              },
              child: Text('返回第一頁'),
            ),
          ],
        ),
      ),
    );
  }
}
複製代碼

運行代碼,跳轉到第二頁,效果以下所示。

Zc1Z4I.png

3.2 頁面跳轉返回數據

除了頁面跳轉須要傳遞數據,有時還須要從第二個頁面返回數據,改寫3.1小節的SecondPage註釋1處的代碼。

Navigator.pop(context,CustomArgumnets('Android進階解密'));
複製代碼

接着改寫FirstPage,以下所示。

class FirstPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("第一頁"),
      ),
      body: Center(
        child: RaisedButton(
          child: Text("跳轉到第二頁"),
          onPressed: () {
            _navigateToSecondPage(context);
          },
        ),
      ),
    );
  }
  _navigateToSecondPage(BuildContext context) async {
    dynamic customArgumnets = await Navigator.pushNamed(context, '/Second',
        arguments: CustomArgumnets('Android進階之光'));//1
    print(customArgumnets.content);
  }
}
複製代碼

註釋1處的代碼能夠接java收返回的結果,而且使用異步來防止阻塞UI。最後貼上完整的代碼。

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "Flutter",
      initialRoute: '/First',
      routes: {
        '/First': (context) => FirstPage(),
        "/Second": (context) => SecondPage()
      },
      home: FirstPage(),
    );
  }
}

class FirstPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("第一頁"),
      ),
      body: Center(
        child: RaisedButton(
          child: Text("跳轉到第二頁"),
          onPressed: () {
            _navigateToSecondPage(context);
          },
        ),
      ),
    );
  }
  _navigateToSecondPage(BuildContext context) async {
    dynamic customArgumnets = await Navigator.pushNamed(context, '/Second',
        arguments: CustomArgumnets('Android進階之光'));
    print(customArgumnets.content);
  }
}

class SecondPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final CustomArgumnets customArgumnets =ModalRoute.of(context).settings.arguments;
    return Scaffold(
      appBar: AppBar(
        title: Text("第二頁"),
      ),
      body: Center(
        child: Column(
          children: <Widget>[
            Text('第一頁的數據爲:'),
            Text(customArgumnets.content),
            RaisedButton(
              onPressed: () {
                Navigator.pop(context,CustomArgumnets('Android進階解密'));
              },
              child: Text('返回第一頁'),
            ),
          ],
        ),
      ),
    );
  }
}
class CustomArgumnets {
  String content;
  CustomArgumnets(this.content);
}
複製代碼

運行程序,當咱們點擊返回第一頁,在控制檯中會打印出 Android進階解密。

Flutter基礎系列
Flutter基礎(一)移動開發的跨平臺技術演進
Flutter基礎(二)Flutter開發環境搭建和Hello World
Flutter基礎(三)Dart快速入門
Flutter基礎(四)開發Flutter應用前須要掌握的Basic Widget
Flutter基礎(五)Material組件之MaterialApp、Scaffold、AppBar
Flutter基礎(六)Material組件之BottomNavigationBar、TabBar、Drawer
Flutter基礎(七)Scrolling Widget之ListView、GridView、PageView
Flutter基礎(八)手勢相關Widget:GestureDetector和Dismissible
Flutter基礎(九)資源和圖片
Flutter基礎(十)佈局Widget快速入門
Flutter基礎(十一)網絡請求(Dio)與JSON數據解析
Flutter基礎(十二)路由(頁面跳轉)與數據傳遞
Flutter基礎(十三)Flutter與Android的相互通訊


這裏不只分享大前端、Android、Java等技術,還有程序員成長類文章。
相關文章
相關標籤/搜索