Flutter學習之路由與導航
簡介
大多數應用程式具有多個頁面或檢視,並且希望將使用者從頁面平滑過渡到另一個頁面。Flutter的路由和導航功能可幫助管理應用中螢幕之間的命名和過渡。
管理多個頁面時有兩個核心概念和類:Route
和 Navigator
。 一個 route
是一個螢幕或頁面的抽象,Navigator
是管理 route
的 Widget
。Navigator
可以通過 route
入棧和出棧來實現頁面之間的跳轉。
Navigator 導航
遇到的坑
在測試的時候,遇到過一個問題,問題就是在於 void main() => runApp(new IndexPage())
。就是不能用這種寫法。
import 'package:flutter/material.dart'; import './item.dart'; void main() => runApp(new IndexPage()); class IndexPage extends StatelessWidget { @override Widget build(BuildContext context){ return new MaterialApp( title: "測試", home: new Scaffold( appBar: new AppBar(title: new Text('第一個介面'),), body: new Center( child: new RaisedButton(onPressed: (){ print(context); // IndexPage Navigator.push(context, new MaterialPageRoute(builder: (context) => new ItemPage() )); }, child: new Text('跳轉'),), ), ), ); } }
這裡後來看了下官網,MaterialApp的主頁成為導航器堆疊底部的路徑。然後自己理解是:導航需要有一個根部的堆疊,然後 new MaterialApp(home: new MyAppHome())
這裡的 home 就充當了根部。
通過 void main() => runApp(new IndexPage())
就是相對於是一個應用跳轉到另外一個應用。
void main() {
runApp(new MaterialApp(home: new MyAppHome()));
}
使用 Navigator.push
就是表示跳轉到新的介面, 使用 Navigator.pop
就是返回上一個介面。邏輯其實就是將 一個介面加入到 Navigator 的堆疊中(push操作),然後將這個頁面移出 Navigator 的堆疊(pop操作)。
在使用 Navigator.push
與 Navigator.pop
的時候,需要傳入一個引數 context
, 這個引數值表示當前的介面 。
完整程式碼例項
import 'package:flutter/material.dart';
/// 跳轉到新頁面並返回
void main() {
runApp(new MaterialApp(
title: "測試", //application名字
home: new IndexPage(), //初始化頁面
));
}
/// 第一個頁面
class IndexPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar( title: new Text("第一個頁面") ),
body: new Center(
child: new RaisedButton(
child: new Text("點選跳轉"),
onPressed: () {
print(context); // 列印值:IndexPage
//跳轉到新的 頁面我們需要呼叫 navigator.push方法
Navigator.push(
context,
new MaterialPageRoute( builder: (context) => new ItemPage()) );
}),
),
);
}
}
/// 第二個頁面
class ItemPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar( title: new Text("第二個頁面") ),
body: new Center(
//onPressed 點選事件
child: new RaisedButton(
child: new Text("點我回第一個頁面"),
onPressed: () {
//回到上一個頁面 相當於finsh
Navigator.pop(context);
}
),
),
);
}
}
使用下面這種方式也是可以實現
void main() {
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
// home 的值必須為 new PageName(), 這樣子才能讓 home 成為導航器堆疊底部的路徑
home: new IndexPage(title: '應用程式首頁'),
);
}
}
跳轉的方法可以獨立出來,下面的寫法也是可以的,使用 Navigator.of(context).push
。
class IndexPage extends StatelessWidget {
@override
Widget build(BuildContext context){
// 點選跳轉的方法
_onPressed(){
// Navigator.push(context, new MaterialPageRoute(builder: (context) => new ItemPage() ));
Navigator.of(context).push(new MaterialPageRoute(builder: (context) => new ItemPage() ));
}
return new Scaffold(
appBar: new AppBar(title: new Text('第一個介面'),),
body: new Center(
// 將點選的方法單獨出去
child: new RaisedButton(onPressed:_onPressed, child: new Text('跳轉'),),
),
);
}
}
使用命名的路由導航
簡單的理解就是說,將對應的路由定義在一個路由表中 Map<String, WidgetBuilder>
,類似於'/a/b/c'
。
void main() {
runApp(new MaterialApp(
home: new MyAppHome(), // becomes the route named '/'
// 設定路由表
// 訪問 /a 就會跳轉到 MyPage1 頁面
// 訪問 /b 就會跳轉到 MyPage2 頁面
// 訪問 /c 就會跳轉到 MyPage3 頁面
routes: <String, WidgetBuilder> {
'/a': (BuildContext context) => new MyPage1(title: 'page A'),
'/b': (BuildContext context) => new MyPage2(title: 'page B'),
'/c': (BuildContext context) => new MyPage3(title: 'page C'),
},
));
}
跳轉到某個路由
Navigator.pushNamed(context, '/b');
完整的程式碼例項
import 'package:flutter/material.dart';
void main() {
runApp(new MaterialApp(
title: "測試",
home: new IndexPage(),
// 新增路由表
routes: <String, WidgetBuilder> {
'/a' : (BuildContext context) => new IndexPage(),
'/b' : (BuildContext context) => new ItemPage(),
},
));
}
class IndexPage extends StatelessWidget{
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(title: new Text("第一個介面"), ),
body: new Center(
child: new RaisedButton(onPressed: (){
// 使用 Navigator.pushNamed(context, '/a') 跳轉
Navigator.pushNamed(context, '/b');
}, child: new Text("點選跳轉到第二個介面"),),
)
);
}
}
class ItemPage extends StatelessWidget{
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(title: new Text("第二個介面"), ),
body: new Center(
child: new RaisedButton(onPressed: (){
Navigator.pushNamed(context, '/a');
}, child: new Text("點選跳轉到第一個介面"),),
)
);
}
}
圖示: