1. 程式人生 > >Flutter學習之路由與導航

Flutter學習之路由與導航

簡介

大多數應用程式具有多個頁面或檢視,並且希望將使用者從頁面平滑過渡到另一個頁面。Flutter的路由和導航功能可幫助管理應用中螢幕之間的命名和過渡。

管理多個頁面時有兩個核心概念和類:RouteNavigator。 一個 route 是一個螢幕或頁面的抽象,Navigator 是管理 routeWidgetNavigator 可以通過 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.pushNavigator.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("點選跳轉到第一個介面"),),
        )
    );
  }
}

圖示:

圖示