導向到一個新頁面和回傳

我們通常會用『屏』來表示應用的不同頁面(介面)。比如,某個應用有一『屏』展示商品清單,當用戶點選某個商品的圖片,會跳到新的一『屏』展示商品的詳細訊息。

在 Android 開發中,Activity 相當於『路由』,在 iOS 開發中,ViewController 相當於『路由』。在 Flutter 中,『路由』也是一個 widget。

怎麼樣從一個『路由』跳轉到新的『路由』呢?Navigator 類。

這個教程裡我們使用 Navigator 來跳轉到一個新的『路由』:

步驟

下面來展示如何在兩個路由間跳轉,總共分三步:

  1. 建立兩個路由

  2. 用 Navigator.push() 跳轉到第二個路由

  3. 用 Navigator.pop() 回退到第一個路由

1. 建立兩個路由

首先,我們來建立兩個路由。這是個最簡單的例子,每個路由只包含一個按鈕。點選第一個路由上的按鈕會跳轉到第二個路由,點選第二個路由上的按鈕,會回退到第一個路由。

首先來編寫介面佈局程式碼:

class FirstRoute extends StatelessWidget {
  const FirstRoute({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('First Route'),
      ),
      body: Center(
        child: ElevatedButton(
          child: const Text('Open route'),
          onPressed: () {
            // Navigate to second route when tapped.
          },
        ),
      ),
    );
  }
}

class SecondRoute extends StatelessWidget {
  const SecondRoute({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Second Route'),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            // Navigate back to first route when tapped.
          },
          child: const Text('Go back!'),
        ),
      ),
    );
  }
}

2. 用 Navigator.push() 跳轉到第二個路由

使用 Navigator.push() 方法跳轉到新的路由, push() 方法會新增一個 Route 物件到導向器的堆疊上。那麼這個 Route 物件是從哪裡來的呢?你可以自己實現一個,或者直接使用 MaterialPageRoute 類。使用 MaterialPageRoute 是非常方便的,框架已經為我們實現了和平台原生類似的切換動畫。

FirstRoute widget 的 build() 方法中,我們來修改 onPressed() 回呼函式:

// Within the `FirstRoute` widget
onPressed: () {
  Navigator.push(
    context,
    MaterialPageRoute(builder: (context) => const SecondRoute()),
  );
}

3. 用 Navigator.pop() 回退到第一個路由

怎麼關閉第二個路由回退到第一個呢? 使用 Navigator.pop() 方法, pop() 方法會從導向器堆疊上移除 Route 物件。

實現回傳第一個頁面,更新 SecondRoute widget 的 onPressed() 方法回呼。

// Within the SecondRoute widget
onPressed: () {
  Navigator.pop(context);
}

互動式範例

import 'package:flutter/material.dart';

void main() {
  runApp(const MaterialApp(
    title: 'Navigation Basics',
    home: FirstRoute(),
  ));
}

class FirstRoute extends StatelessWidget {
  const FirstRoute({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('First Route'),
      ),
      body: Center(
        child: ElevatedButton(
          child: const Text('Open route'),
          onPressed: () {
            Navigator.push(
              context,
              MaterialPageRoute(builder: (context) => const SecondRoute()),
            );
          },
        ),
      ),
    );
  }
}

class SecondRoute extends StatelessWidget {
  const SecondRoute({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Second Route'),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            Navigator.pop(context);
          },
          child: const Text('Go back!'),
        ),
      ),
    );
  }
}

In the previous example you learned how to navigate between screens using the MaterialPageRoute from Material Components. However, in Flutter you are not limited to Material design language, instead, you also have access to Cupertino (iOS-style) widgets.

Implementing navigation with Cupertino widgets follows the same steps as when using MaterialPageRoute, but instead you use CupertinoPageRoute which provides an iOS-style transition animation.

In the following example, these widgets have been replaced:

This way, the example follows the current iOS design language.

import 'package:flutter/cupertino.dart';

void main() {
  runApp(const CupertinoApp(
    title: 'Navigation Basics',
    home: FirstRoute(),
  ));
}

class FirstRoute extends StatelessWidget {
  const FirstRoute({super.key});

  @override
  Widget build(BuildContext context) {
    return CupertinoPageScaffold(
      navigationBar: const CupertinoNavigationBar(
        middle: Text('First Route'),
      ),
      child: Center(
        child: CupertinoButton(
          child: const Text('Open route'),
          onPressed: () {
            Navigator.push(
              context,
              CupertinoPageRoute(builder: (context) => const SecondRoute()),
            );
          },
        ),
      ),
    );
  }
}

class SecondRoute extends StatelessWidget {
  const SecondRoute({super.key});

  @override
  Widget build(BuildContext context) {
    return CupertinoPageScaffold(
      navigationBar: const CupertinoNavigationBar(
        middle: Text('Second Route'),
      ),
      child: Center(
        child: CupertinoButton(
          onPressed: () {
            Navigator.pop(context);
          },
          child: const Text('Go back!'),
        ),
      ),
    );
  }
}