flutter之從零開始搭建(二)之 Navigator路由

codelang發表於2019-03-04

今天我們來講講利用Navigator來跳轉頁面的功能,承接上一篇flutter之從零開始搭建(一)之 BottomNavigationBar繼續講。

頁面跳轉是我們在入門學習的必備知識,在flutter中,路由跳轉是由Navigator來操作的。

Navigator的跳轉有兩種,一種是顯示跳轉,需要我們在MaterialPageRoute中指定widget

  Navigator.of(context).push(new MaterialPageRoute(builder: (context) {
      //指定跳轉的頁面
      return new Demo1();
    },));
複製程式碼

另一種是隱身跳轉,這種跳轉需要先定義,後使用,跳轉方式就像Arouter一樣的路徑方式,定義部分需要在MaterialApp下定義routes,routes就跟一個Map<path,Page>集合一樣,定義好了path對應的page,那麼下次跳轉,我們就可以針對path去跳轉了

 @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      home: new Scaffold(
        body: new Center(child: new RaisedButton(onPressed: _pushPage,child: new Text("跳轉"))),
      ),
      //定義路由
      routes: <String,WidgetBuilder>{
        "/demo1":(BuildContext context)=>new Demo1(),
      },
    );
複製程式碼

跳轉使用

 Navigator.of(context).pushNamed("/demo1");
複製程式碼

知道路由如何跳轉了,那麼,我們開始實戰吧

實戰

我們看到,路由的跳轉都帶著一個context引數,這其中有無數的坑需要自己去理解,接下來我會展示出來。

還是承接上一篇博文flutter之從零開始搭建(一)之 BottomNavigationBar,我們先看下MyPage頁面,先給出如下程式碼

import 'package:flutter/material.dart';
import 'package:codelang/widget/Demo1.dart';

class MyPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      debugShowCheckedModeBanner: false,
      home: new PageWidget(),
      routes: <String,WidgetBuilder>{
        "/demo1":(BuildContext context)=>new Demo1(),
      },
    );
  }
}

class PageWidget extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return new PageState();
  }
}

class PageState extends State<PageWidget> {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
       body: new Center(child: new RaisedButton(onPressed: _pushPage,child: new Text("跳轉"),),),
    );
  }
  _pushPage(){
   // Navigator.of(context).pushNamed("/demo1");
    Navigator.of(context).push(new MaterialPageRoute(builder: (context) {
      return new Demo1();
    },));
  }
}

複製程式碼

大家整體看一下程式碼,其實沒什麼錯誤的地方,看起來一切都很正常,然後我們來看下效果圖

image

what fuck!!! 跳轉的頁面怎麼沒有覆蓋全屏,所以,這種方式肯定是不可取的。

我們先停下來想想,我們當前頁面PageState是在PageWidget佈局上面,PageWidget還有一個上層佈局叫MyPage,我們是不是可以理解為,Navigator.of(context)的這個context指向的是上層MyPage佈局的context,導致了頁面路由跳轉是在MyPage頁面進行。

那麼有什麼解決辦法呢?既然是context原因,那麼,我們必須得拿到MyPage的上一層context,我們再想想,MyPage相當於一個fragment,是由MainPage頁面組成的,我們只需要拿將MainPage頁面的context傳遞給MyPage不就行了嗎?接下來開幹試試。

開啟MainPage

給MyPage的構造方法傳遞MainPage的context

    _bodys = [
      new HomePage(),
      new ShopPage(),
      new MsgPage(),
      new MyPage(context)
    ];
複製程式碼

開啟MyPage

MyPage拿到MainPage的parentContext,然後將parentContext傳遞給PageWidgetPageState可以通過widget.X的形式,可以拿到PageWidget的變數

import 'package:flutter/material.dart';
import 'package:codelang/widget/Demo1.dart';

class MyPage extends StatelessWidget {
  var parentContext;
  MyPage(this.parentContext);
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter Demo',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      debugShowCheckedModeBanner: false,
      home: new PageWidget(parentContext),
      routes: <String,WidgetBuilder>{
        "/demo1":(BuildContext context)=>new Demo1(),
      },
    );
  }
}

class PageWidget extends StatefulWidget {
  var parentContext;

  PageWidget(this.parentContext);
  @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return new PageState();
  }
}

class PageState extends State<PageWidget> {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
       body: new Center(child: new RaisedButton(onPressed: _pushPage,child: new Text("跳轉"),),),
    );
  }
  _pushPage(){
//    Navigator.of(widget.parentContext).pushNamed("/demo1");

    Navigator.of(widget.parentContext).push(new MaterialPageRoute(builder: (context) {
      return new Demo1();
    },));
  }
}
複製程式碼

看下效果圖

image

嗯,很完美的解決,大家有沒有看到我_pushPage方法中註釋了的pushNamed方式的跳轉,大家猜猜,用這種方式會不會出錯?5秒鐘的思考哦.

  • 倒數計時5s
  • 倒數計時4s
  • 倒數計時3s
  • 倒數計時2s
  • 倒數計時1s

OK,來揭曉答案,肯定是不行的,我們知道,routes的定義是在MyPage中的,而我們餓路由跳轉拿到的parentContextMainPage的,所以,會報找不到這個路由的錯誤,如何解決呢?我相信到這大家應該都清楚了,那就是在MainPage中去定義這個routes,具體可以看如下

class MainPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
        debugShowCheckedModeBanner: false,
        routes: <String, WidgetBuilder>{
          "/demo1": (BuildContext context) => new Demo1(),
        },
        home: new MainPageWidget());
  }
}
複製程式碼

這樣跳轉就可以了,效果圖我就不貼出來了,跟上面一樣。


你以為就這樣結束了?哈哈,早著呢,在寫這篇博文的時候,我又發現了一個好玩的地方,為了區分,我在HomePage頁面去寫這個例子,程式碼不多,大家看看

HomePage

import 'package:flutter/material.dart';
import 'package:codelang/widget/Demo1.dart';

class HomePage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return new HomeState();
  }
}

class HomeState extends State<HomePage> {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return new MaterialApp(
      debugShowCheckedModeBanner: false,
      home: new Scaffold(
        body: new Center(child: new RaisedButton(onPressed: _pushPage,child: new Text("跳轉"))),
      ),
    );
  }
  _pushPage() {
//    Navigator.of(context).pushNamed("/demo1");
    Navigator.of(context).push(new MaterialPageRoute(builder: (context) {
      return new Demo1();
    },));
  }
}
複製程式碼

在這個路由跳轉中,我用了context來跳轉,大家再猜猜,這種方式可以嘛?5秒鐘的思考時間

  • 倒數計時5s
  • 倒數計時4s
  • 倒數計時3s
  • 倒數計時2s
  • 倒數計時1s

答案揭曉,是可以的哦,為什麼這樣又可以了呢?

HomePageMyPage的區別在於定義這個widget時,MyPage最外套的一層是StatelessWidget,而HomePage最外套的一層是StatefulWidgetStatelessWidget是一個無狀態的widget,難道是他阻隔了context的傳遞?具體的我也不清楚,只能去猜。

大家再猜猜還是那段註釋了的pushNamed的程式碼,可不可以跳轉呢?哈哈,當然是可以的,因為我們在前面的時候,就已經在mainPage中定義了routes


好了,路由這篇說完了,唯一坑就是context的問題,看了這一篇,相信很多人都理解了Navigator如何跳轉,下一篇再見吧

gayhub連結

相關文章