Flutter 路由跳轉及傳值詳解(Navigator的使用)

在 Flutter 中想要實現頁面間的跳轉和傳值的話,離不開兩種路由:git

  • 基本路由
  • 命名式路由

官方說的是靜態路由和動態路由,不過我習慣了這樣叫,因此就暫且這樣說吧!bash

基本路由

基本跳轉

基本路由的跳轉
使用push跳到指定的頁面,而後再使用pop回到原來的頁面app

不過當你跳轉過去的時候,人家默認會有一個返回的箭頭按鈕,點擊就能夠返回less

開始擼代碼異步

我在main.dart文件中引用了Home.dart文件
Home.dart文件中有一個按鈕,當我點擊的時候,能夠跳到詳情頁面async

注:若是用stl生成的靜態控件是不能用跳轉按鈕的ide

Home.dart文件代碼:測試

//Home.dart
import 'package:flutter/material.dart';
import './Detail.dart';

class Home extends StatefulWidget {
  @override
  _HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: <Widget>[
          RaisedButton(
            child: Text('跳到詳情頁面'),
            onPressed: (){
              //跳轉頁面
              Navigator.of(context).push(
                MaterialPageRoute(
                  //沒有傳值
                  builder: (context)=>Detail()
                )
              );
            },
          )
        ],
      ),
    );
  }
}
複製代碼

當我點擊了按鈕的時候,就能夠跳到詳情頁面:
Detail.dart文件代碼:優化

import 'package:flutter/material.dart';

class Detail extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      //浮動按鈕
      floatingActionButton: FloatingActionButton(
        child: Text('返回'),
        onPressed: (){
          Navigator.of(context).pop();
        },
      ),
      appBar: AppBar(title: Text("詳情頁面"),),
      body: Text("詳情頁面"),
    );
  }
}
複製代碼

如圖,跳過去後默認會有一個返回按鈕,點擊後就能夠返回 ,
也能夠本身定義一個按鈕,利用pop方法點擊後也能夠返回ui

圖片加載失敗!

跳轉傳值

有時候咱們跳轉的時候須要傳遞參數,
這時候咱們就要攜帶參數跳轉,固然很是簡單

咱們須要在使用參數的頁面定義一個變量,注意須要設置默認值,若是沒給你傳值的時候使用默認值
而後在跳轉的時候給目標頁面傳值

Home.dart文件代碼:

//Home.dart
//只貼按鈕的代碼,其他的和上面同樣

RaisedButton(
	child: Text('跳到詳情頁面'),
	onPressed: (){
	  //跳轉頁面
	  Navigator.of(context).push(
		MaterialPageRoute(
		  //傳值
		  builder: (context)=>Detail(Test:'我是參數')
		  //沒傳值
		  //builder: (context)=>Detail()
		)
	  );
	},
  )
複製代碼

而後在目標頁面接收,若是沒傳值默認爲上面定義的默認值

Detail.dart文件代碼:

class Detail extends StatelessWidget {
  //須要定義變量和默認值
  String Test;
  Detail({this.Test='沒有給我傳值'});
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      //浮動按鈕
      floatingActionButton: FloatingActionButton(
        child: Text('返回'),
        onPressed: (){
          Navigator.of(context).pop();
        },
      ),
      appBar: AppBar(title: Text("詳情頁面"),),
      body: Text(this.Test),
    );
  }
}
複製代碼

圖片加載失敗!

返回時接收值

有時候咱們跳轉的時候不須要傳值,而當你返回的時候須要從子組件中接收值

用下面這個例子來講明:

新建兩個dart文件AddressList.dartGetAddress.dart文件,在mian.dart中使用GetAddress.dart文件

咱們想要點擊GetAddress.dart文件中的 選擇收穫地址 按鈕,跳到添加地址頁面,而後選擇地址後,直接帶着數據返回到首頁面並顯示出來

代碼示例:

main.dart文件只改了須要渲染的控件

import 'package:flutter/material.dart';
import './address/GetAddress.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text("Route"),
        ),
        body: GetAddress()
      ),
    );
  }
}
複製代碼

注意獲取數據都是異步的,須要加async、await
改變數據的惟一方式是利用setState方法

GetAddress.dart文件代碼:

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

class GetAddress extends StatefulWidget {
  @override
  _GetAddressState createState() => _GetAddressState();
}

class _GetAddressState extends State<GetAddress> {
  //定義一個變量
  String _ads = '';
  
  @override
  Widget build(BuildContext context) {
    return Container(
      child: Scaffold(
        appBar: AppBar(title: Text('獲取收穫地址'),),
        body: Center(
          child: Column(
            //垂直居中
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              RaisedButton(
                //按鈕主題
                textTheme: ButtonTextTheme.primary,
                color: Theme.of(context).accentColor,
                child: Text('選擇收貨地址'),
                //點擊
                onPressed: () async {
                    //經過路由跳轉從子頁面中傳遞過來的數據,都是異步的
                    var ads = await Navigator.of(context).push(
                      MaterialPageRoute(
                        builder: (BuildContext context){
                          return AddressList();
                        }
                      )
                    );
                    setState(() {
                     _ads = ads; 
                    });
                },
              ),
              Text('${_ads==""?"未查到收貨地址":_ads}')
            ],
          ),
        ),
      ),
    );
  }
}
複製代碼

利用onTap點擊後直接使用pop返回到首頁面,並把數據帶回去

AddressList.dart文件代碼:

import 'package:flutter/material.dart';

class AddressList extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("個人地址列表"),),
      body: ListView(
        padding: EdgeInsets.all(10),
        children: <Widget>[
          GestureDetector(
            onTap: (){
              //pop後面能夠跟上參數
              Navigator.of(context).pop('北京');
            },
            //給子組件添加事件
            child: Container(
              decoration: BoxDecoration(
                border: Border.all(color: Colors.black26)
              ),
              child: ListTile(
                leading: Icon(
                  Icons.account_box,
                  color: Colors.blue,
                ),
                title: Text(
                  '北京',
                  maxLines: 1,
                  overflow: TextOverflow.ellipsis,
                ),
              ),
            ),
          ),
          //給控件中間加間隙
          SizedBox(height: 10),
          GestureDetector(
            onTap: (){
              //pop後面能夠跟上參數
              Navigator.of(context).pop('河南');
            },
            //給子組件添加事件
            child: Container(
              decoration: BoxDecoration(
                border: Border.all(color: Colors.black26)
              ),
              child: ListTile(
                leading: Icon(
                  Icons.account_box,
                  color: Colors.blue,
                ),
                title: Text(
                  '河南',
                  maxLines: 1,
                  overflow: TextOverflow.ellipsis,
                ),
              ),
            ),
          ),
          //給控件中間加間隙
          SizedBox(height: 10),
          GestureDetector(
            onTap: (){
              //pop後面能夠跟上參數
              Navigator.of(context).pop('上海');
            },
            //給子組件添加事件
            child: Container(
              decoration: BoxDecoration(
                border: Border.all(color: Colors.black26)
              ),
              child: ListTile(
                leading: Icon(
                  Icons.account_box,
                  color: Colors.blue,
                ),
                title: Text(
                  '上海',
                  maxLines: 1,
                  overflow: TextOverflow.ellipsis,
                ),
              ),
            ),
          )
        ],
      ),
    );
  }
}
複製代碼

圖片加載失敗!

命名式路由

相似於 Vue 中的路由

基本跳轉

新建了幾個頁面Main.dartPage1.dartPage1.dartPage3.dart 用來測試

引入文件,
main.dart中的routes中配置路徑(必須在main.dart中配置)
body換成須要渲染的頁面

main.dart文件代碼:

import 'package:flutter/material.dart';
import './files/Page1.dart';
import './files/Page2.dart';
import './files/Page3.dart';

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text("Route"),
        ),
        body: Main(),
      ),
      //定義路由
      routes: {
        //須要使用context指定上下文
        '/page1': (context) => Page1(),
        '/page2': (context) => Page2(),
        '/page3': (context) => Page3(),
      },
    );
  }
}
複製代碼

Main.dart文件中寫兩個按鈕用來跳轉(注意一個是main.dart一個是Main.dart

Main.dart文件代碼:

import 'package:flutter/material.dart';

class Main extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Center(
          child: Column(
            children: <Widget>[
              //定義按鈕
              RaisedButton(
                  child: Text("跳轉到Page1"),
                  onPressed: () {
                    //須要使用pushNamed方法
                    Navigator.pushNamed(context, "/page1");
                  },
              ),
              SizedBox(height: 20),
              RaisedButton(
                  child: Text("跳轉到Page2"),
                  onPressed: () {
                    Navigator.pushNamed(context, "/page2");
                  },
              ),
            ],
          ),
        ),
      ),
    );
  }
}
複製代碼

點擊按鈕跳轉到指定頁面,Page1.dartPage2.dartPage3.dart頁面的基本結構,只貼一個頁面看一下:

Page1.dart文件代碼:

import 'package:flutter/material.dart';

class Page1 extends StatefulWidget {
  @override
  _Page1State createState() => _Page1State();
}
class _Page1State extends State<Page1> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Page1"),),
      body: Text("Page1",style: TextStyle(fontSize: 40),),
    );
  }
}
複製代碼

圖片加載失敗!

路由抽離跳轉

通常咱們使用命名式路由的話,不用上面的方式,咱們都是單獨把路由抽離出去

優化上面的代碼:

新建一個Routes.dart文件用來存放路由規則,

Routes.dart文件代碼:

import 'package:flutter/material.dart';
//引入文件
import '../files/Main.dart';
import '../files//Page1.dart';
import '../files//Page2.dart';
import '../files//Page3.dart';

//配置路由規則
final routes = {
  '/': (context) => Main(),
  '/page1': (context) => Page1(),
  '/page2': (context) => Page2(),
  '/page3': (context) => Page3(),
};

// 若是你要把路由抽離出去,必須寫下面這一堆的代碼,不用理解什麼意思
var onGenerateRoute = (RouteSettings settings) {
  // 統一處理
  final String name = settings.name;
  final Function pageContentBuilder = routes[name];
  if (pageContentBuilder != null) {
    if (settings.arguments != null) {
      final Route route = MaterialPageRoute(
          builder: (context) =>
              pageContentBuilder(context, arguments: settings.arguments));
      return route;
    } else {
      final Route route =
          MaterialPageRoute(builder: (context) => pageContentBuilder(context));
      return route;
    }
  }
};

複製代碼

而後在main.dart文件中配置使用:

import 'package:flutter/material.dart';
//引入Routes.dart文件
import './routes/Routes.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      initialRoute: '/',  //配置默認訪問路徑
      onGenerateRoute:onGenerateRoute,  //必須加上這一行,固定寫法
    );
  }
}
複製代碼

配置好後,別的地方都不用動,這樣就實現了咱們的路由抽離

跳轉傳值

緊跟着上面的代碼,當咱們使用命名式路由,而且把路由抽離後進行跳轉時,咱們想要跳轉過去的時候給他傳值,那麼怎麼辦呢?很簡單

在上面代碼的基礎上改動

改變Main.dart文件中的按鈕方法,當跳轉的時候傳值,以下:

只粘貼第二個跳轉按鈕,別的代碼不用動

RaisedButton(
	  child: Text("跳轉到Page2"),
	  onPressed: () {
		Navigator.pushNamed(context, "/page2",arguments: {
		  "id":102
		});
	  },
  ),
複製代碼

而後在Routes.dart文件中改變page2路由規則:

'/page2': (context,{arguments}) => Page2(arguments:arguments),
複製代碼

最後在Page2.dart頁面定義變量,重構,接收傳遞過來的值:

import 'package:flutter/material.dart';

class Page2 extends StatefulWidget {
  //定義一個變量
  final arguments;
  //重構
  Page2({this.arguments});
  
  @override
  _Page2State createState() => _Page2State();
}

class _Page2State extends State<Page2> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Page2"),),
      //使用傳遞過來的值
      body: Text("${widget.arguments['id']}",style: TextStyle(fontSize: 40),),
    );
  }
}
複製代碼

圖片加載失敗!

源碼

點擊-->源碼地址


@_@

相關文章
相關標籤/搜索