今天我們來講講利用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();
},));
}
}
複製程式碼
大家整體看一下程式碼,其實沒什麼錯誤的地方,看起來一切都很正常,然後我們來看下效果圖
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傳遞給PageWidget
,PageState
可以通過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();
},));
}
}
複製程式碼
看下效果圖
嗯,很完美的解決,大家有沒有看到我_pushPage
方法中註釋了的pushNamed
方式的跳轉,大家猜猜,用這種方式會不會出錯?5秒鐘的思考哦.
- 倒數計時5s
- 倒數計時4s
- 倒數計時3s
- 倒數計時2s
- 倒數計時1s
OK,來揭曉答案,肯定是不行的,我們知道,routes的定義是在MyPage
中的,而我們餓路由跳轉拿到的parentContext
是MainPage
的,所以,會報找不到這個路由的錯誤,如何解決呢?我相信到這大家應該都清楚了,那就是在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
答案揭曉,是可以的哦,為什麼這樣又可以了呢?
HomePage
與MyPage
的區別在於定義這個widget時,MyPage
最外套的一層是StatelessWidget
,而HomePage
最外套的一層是StatefulWidget
,StatelessWidget
是一個無狀態的widget,難道是他阻隔了context的傳遞?具體的我也不清楚,只能去猜。
大家再猜猜還是那段註釋了的pushNamed
的程式碼,可不可以跳轉呢?哈哈,當然是可以的,因為我們在前面的時候,就已經在mainPage
中定義了routes
好了,路由這篇說完了,唯一坑就是context的問題,看了這一篇,相信很多人都理解了Navigator如何跳轉,下一篇再見吧