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);
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),
),
);
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,
),
),
);
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'),
),
);
}
}
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(),
);
}
},
)
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 で十分です。中・大規模なアプリケーションでは、名前付きルートやルート管理ライブラリを使用して、ページを一元管理することをお勧めします。