Flutter结合Firestore实现动态路由:根据所选国家加载对应城市页面
Flutter 动态路由+Firestore 数据加载实现方案
1. 路由传参实现
在国家列表页面,给每个国家列表项绑定点击事件,通过RouteSettings传递国家的唯一标识(比如Firestore文档ID或国家名称):
GestureDetector( onTap: () { Navigator.push( context, MaterialPageRoute( builder: (context) => const CityListPage(), // 传递国家标识,这里用Firestore文档ID示例 settings: const RouteSettings(arguments: "china"), ), ); }, child: ListTile(title: const Text("中国")), )
在城市列表页面,通过ModalRoute获取路由参数:
class CityListPage extends StatelessWidget { const CityListPage({super.key}); @override Widget build(BuildContext context) { // 获取路由传递的国家标识 final countryId = ModalRoute.of(context)!.settings.arguments as String; return Scaffold( appBar: AppBar(title: const Text("城市列表")), body: FutureBuilder<List<City>>( future: _loadCities(countryId), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return const Center(child: CircularProgressIndicator()); } if (snapshot.hasError) { return Center(child: Text("加载失败: ${snapshot.error}")); } final cities = snapshot.data ?? []; return ListView.builder( itemCount: cities.length, itemBuilder: (context, index) { final city = cities[index]; return Card( child: Padding( padding: const EdgeInsets.all(8.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Image.network(city.imageUrl, height: 150, width: double.infinity, fit: BoxFit.cover), const SizedBox(height: 8), Text(city.name, style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold)), const SizedBox(height: 4), Text(city.description), ], ), ), ); }, ); }, ), ); } }
2. Firestore数据查询与模型转换
先定义城市数据模型,方便从Firestore文档转换数据:
class City { final String name; final String imageUrl; final String description; City({required this.name, required this.imageUrl, required this.description}); // 从Firestore文档映射为模型 factory City.fromFirestore(DocumentSnapshot doc) { final data = doc.data() as Map<String, dynamic>; return City( name: data['name'] ?? '', imageUrl: data['imageUrl'] ?? '', description: data['description'] ?? '', ); } }
然后实现Firestore查询方法,根据国家标识获取对应城市:
Future<List<City>> _loadCities(String countryId) async { final citiesSnapshot = await FirebaseFirestore.instance .collection('countries') .doc(countryId) .collection('cities') .get(); return citiesSnapshot.docs.map((doc) => City.fromFirestore(doc)).toList(); }
3. Firestore数据结构建议
推荐的数据库层级结构:
countries (集合) ├─ china (文档ID: china) │ └─ cities (子集合) │ ├─ beijing (文档) │ │ ├─ name: "北京" │ │ ├─ imageUrl: "https://example.com/beijing.jpg" │ │ └─ description: "中国首都..." │ ├─ shanghai (文档) │ └─ guangzhou (文档) ├─ usa (文档ID: usa) │ └─ cities (子集合) └─ japan (文档ID: japan) └─ cities (子集合)
4. 数据流向示意图
数据流向:
- 用户点击国家列表页的某个国家 → 路由携带国家ID跳转到城市列表页
- 城市列表页接收国家ID → 向Firestore发起查询请求
- Firestore返回该国家下的所有城市数据 → 城市列表页渲染城市卡片(图片+描述)
内容的提问来源于stack exchange,提问作者Gytis Raudonius
相关产品推荐
相关产品推荐

