Flutter(二十三)——靜態路由與動態路由

前言

前面講解過一些Flutter路由知識,比如講解Hero動畫的時候,就提到過路由的相關知識。其實路由是專業名詞,就是界面切換,而跳轉界面解釋路由跳轉。(下圖爲動態路由實現效果)
動態路由效果實現圖
我們提到過,在Flutter開發中,路由的管理是通過堆棧的方式進行管理的,也就是說基本的用法就是push與pop方式,而在實際的項目中可沒有那麼簡單,頁面之間的跳轉情況比較多,這就涉及到路由棧的管理知識,而路由的種類又分爲靜態路由與動態路由,下面我們分別來講解這兩種路由的方式。

靜態路由

顧名思義,靜態路由就是在知道明確跳往哪個界面時的情況下使用的。比如在MaterialApp構造函數裏,我們可以定義路由列表。我們前面有介紹就是在main的入口函數裏的runApp方法中傳入,具體的代碼使用如下:

import 'package:flutter/material.dart';
import 'package:route_flutter_app/page1.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: '靜態路由',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      routes: {
        '/page1':(context)=>Page1(title: "主頁面",),
        '/page2':(context)=>Page2(title: "第二個頁面",),
        '/page3':(context)=>Page3(title: "第三個頁面",),
        '/page4':(context)=>Page4(title: "第四個頁面",),
      },
      onUnknownRoute: (RouteSettings setting){
        String name=setting.name;
        print("沒有匹配到路由");
        return new MaterialPageRoute(builder: (context){
          return new ErrorPage(title: "沒有匹配的頁面",);
        });
      },
      home: Page1(title: "主頁面",),
    );
  }
}

上面這段代碼中,我們通過home定義了主頁面,routes定義了路由表,page1234就是我們的靜態路由,也就是我們事先知道需要用到哪些界面,就是使用這種方式,而routes的參數是一個Map類型。

特別注意:MaterialApp還有一個屬性,它就是initRoute,這個屬性我們前面的章節也提到過,它指的是App啓動的默認路由,也就是主頁面,如果你使用了這個屬性,那麼就不需要指定home。

通過上面對應的路由表,我們可以直接使用Navigator.pushNamed方法進行跳轉,但是,爲了程序的嚴謹,我們還可以定義一個出錯界面,也就是上面的onUnknownRoute,通過上面代碼跳轉到一個出錯的自定義界面,以避免程序崩潰出錯,增加用用戶體驗。

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

class Page1 extends StatelessWidget{
  final String title;

  Page1({Key key,@required this.title}):super(key:key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(this.title),
      ),
      body: Center(
        child: RaisedButton(
          child: Text("跳轉到page2"),
          onPressed: (){
            Navigator.pushNamed(context, "/page2");
          },
        ),
      ),
    );
  }
}

class Page2 extends StatelessWidget{
  final String title;

  Page2({Key key,@required this.title}):super(key:key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(this.title),
      ),
      body: Center(
        child: RaisedButton(
          child: Text("跳轉到page3"),
          onPressed: (){
            Navigator.pushNamed(context, "/page3");
          },
        ),
      ),
    );
  }
}

class Page3 extends StatelessWidget{
  final String title;

  Page3({Key key,@required this.title}):super(key:key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(this.title),
      ),
      body: Center(
        child: RaisedButton(
          child: Text("跳轉到page4"),
          onPressed: (){
            Navigator.pushNamed(context, "/page4");
          },
        ),
      ),
    );
  }
}

class Page4 extends StatelessWidget{
  final String title;

  Page4({Key key,@required this.title}):super(key:key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(this.title),
      ),
      body: Center(
        child: Text(this.title,style: new TextStyle(fontSize: 50,color: Colors.red),)
      ),
    );
  }
}

class ErrorPage extends StatelessWidget{
  final String title;

  ErrorPage({Key key,@required this.title}):super(key:key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(this.title),
      ),
      body: Center(
          child: Text(this.title,style: new TextStyle(fontSize: 50,color: Colors.red),)
      ),
    );
  }

上面是我們定義的4個跳轉界面,一個出錯界面,代碼都是基本的代碼就不多做講解了,這裏我們的實現效果如下圖所示:
跳轉界面實例
在RaisedButton的onPress裏,我們通過調用方法Navigator.pushNamed(context, “/page4”),這樣就可以跳轉到定義的路由表界面,當然也可以使用前面的push方法:

Navigator.of(context).push(
	new MaterialPageRoute(
		builder:(context){
			return new Page4()}));

動態路由

雖然靜態路由可以跳轉界面,但是在大多數項目中,我們在兩個界面之間跳轉時需要攜帶參數,比如很多新聞類的App從列表跳轉到新聞詳情的界面。這個時候,動態路由就起作用了。下面我們先來看看代碼,看動態路由是如何實現的,首先我們定義一個列表用到的新聞類News:

class News{
  final String title;
  final String description;
  
  New(this.title,this.description);
}

這裏小編定義了一個新聞類,新聞類有兩個變量,一個標題,一個詳細情況,接着我們直接修改上面主頁面page1的代碼,如下所示:

class Page1 extends StatelessWidget{
  final String title;

  Page1({Key key,@required this.title}):super(key:key);

  final news=List<News>.generate(20, (i)=>News("新聞 $i","新聞 $i的詳細信息"),);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(this.title),
      ),
      body: ListView.builder(itemBuilder: (context,index){
        return ListTile(
          title: Text(news[index].title),
          onTap: (){
            Navigator.push(
              context,
              MaterialPageRoute(
                builder: (context)=>NewsDetail(s_new: news[index],),
              )
            );
          },
        );
      },
        itemCount: news.length,
      ),
    );
  }
}

這裏首先生成了一個20個元素的新聞列表,通過generate方法可以快速創建一個列表,接着通過ListView.builder方法生成listView列表,每個列表是一個ListTile,通過onTap方法監聽點擊事件,這裏將點擊的新聞類傳遞給NewsDetail詳情界面:

Navigator.push(
    context,
    MaterialPageRoute(
        builder: (context)=>NewsDetail(s_new: news[index],),
    )
);

接着我們來看看我們詳情界面的設置,代碼如下:

class NewsDetail extends StatelessWidget{
  final News s_new;

  NewsDetail({Key key,@required this.s_new}):super(key:key);
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(this.s_new.title),),
      body: Center(
        child: Text(this.s_new.description),
      ),
    );
  }

}

這裏也就一個常規的代碼片段,定義了一個標題,居中顯示新聞的詳情內容,然後我們就實現瞭如博文開頭所示的操作。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章