Flutter ナビゲーションとルーティング

このセクションでは、Flutter におけるナビゲーションとルーティングの仕組みを紹介します。ページ遷移、パラメータの受け渡し、名前付きルートなどを含みます。


Navigator の基礎

Flutter は Navigator を使用してページを管理し、スタック構造に基づいてページ遷移を実現します。

例:基本的なページ遷移

// 跳转到新页面
Navigator.of(context).push(
  MaterialPageRoute(
    builder: (context) => const DetailPage(),
  ),
);

// 返回上一页
Navigator.of(context).pop();

// 带结果返回
Navigator.of(context).pop('返されたデータ');

// 替换当前页面(不可返回)
Navigator.of(context).pushReplacement(
  MaterialPageRoute(
    builder: (context) => const HomePage(),
  ),
);

// 回到根页面
Navigator.of(context).popUntil((route) => route.isFirst);

MaterialPageRoute vs CupertinoPageRoute

例:プラットフォーム別のページ切り替えアニメーション

// Android スタイル - 下部からスライドアップ
Navigator.of(context).push(
  MaterialPageRoute(
    builder: (context) => const DetailPage(),
  ),
);

// iOS スタイル - 右側からスライドイン
Navigator.of(context).push(
  CupertinoPageRoute(
    builder: (context) => const DetailPage(),
  ),
);

// 自定义过渡效果
Navigator.of(context).push(
  PageRouteBuilder(
    pageBuilder: (context, animation, secondaryAnimation) {
      return const DetailPage();
    },
    transitionsBuilder: (context, animation, secondaryAnimation, child) {
      // 淡入淡出效果
      return FadeTransition(
        opacity: animation,
        child: child,
      );
    },
    transitionDuration: const Duration(milliseconds: 300),
  ),
);

ページのパラメータ受け渡し

< h2 class="example">例:新しいページへパラメータを渡す
// 跳转到详情页并传递参数
Navigator.of(context).push(
  MaterialPageRoute(
    builder: (context) => ProductDetailPage(productId: 123),
  ),
);

// 详情页接收参数
class ProductDetailPage extends StatelessWidget {
  final int productId;

  const ProductDetailPage({
    super.key,
    required this.productId,
  });

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('商品 $productId')),
      body: Center(child: Text('商品 ID: $productId')),
    );
  }
}

// 传递多个参数
class UserProfilePage extends StatelessWidget {
  final String name;
  final int age;

  const UserProfilePage({
    super.key,
    required this.name,
    required this.age,
  });

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('$name のホームページ')),
      body: Center(child: Text('年龄: $age')),
    );
  }
}

// 跳转
Navigator.of(context).push(
  MaterialPageRoute(
    builder: (context) => const UserProfilePage(
      name: '张三',
      age: 25,
    ),
  ),
);

名前付きルート

名前付きルートを使用すると、ページ遷移の設定を簡素化できます。

例:名前付きルートの設定

void main() {
  runApp(
    MaterialApp(
      // 定义路由表
      initialRoute: '/',
      routes: {
        '/': (context) => const HomePage(),
        '/detail': (context) => const DetailPage(),
        '/user': (context) => const UserPage(),
        '/settings': (context) => const SettingsPage(),
      },
    ),
  );
}

// 跳转
Navigator.pushNamed(context, '/detail');

// 带参数跳转
Navigator.pushNamed(context, '/user', arguments: {'name': '张三', 'age': 25});

// ターゲットページでパラメータを取得する
class DetailPage extends StatelessWidget {
  const DetailPage({super.key});

  @override
  Widget build(BuildContext context) {
    // 渡されたパラメータを取得する
    final args = ModalRoute.of(context)?.settings.arguments as Map?;

    return Scaffold(
      appBar: AppBar(title: const Text('详情页')),
      body: Center(
        child: Text('参数: $args'),
      ),
    );
  }
}

ルートで値を受け渡す別の方法

例:onGenerateRoute

MaterialApp(
  onGenerateRoute: (settings) {
    // 根据路由名称返回不同页面
    switch (settings.name) {
      case '/':
        return MaterialPageRoute(
          builder: (_) => const HomePage(),
        );
      case '/detail':
        // arguments からパラメータを取得する
        final args = settings.arguments as Map<String, dynamic>?;
        return MaterialPageRoute(
          builder: (_) => DetailPage(
            id: args?['id'] ?? 0,
            title: args?['title'] ?? '',
          ),
        );
      case '/product':
        final productId = settings.name?.split('/').last;
        return MaterialPageRoute(
          builder: (_) => ProductPage(id: productId ?? ''),
        );
      default:
        return MaterialPageRoute(
          builder: (_) => const NotFoundPage(),
        );
    }
  },
)

シンプルなアプリケーションであれば、基本的な Navigator.push で十分です。中・大規模なアプリケーションでは、名前付きルートやルート管理ライブラリを使用して、ページを一元管理することをお勧めします。

その他の拡張