Flutter餐厅菜单应用如何传参复用单页动态加载不同JSON数据
实现方案
你只需要调整首页传参逻辑、复用列表页代码做一个通用页即可,无需为每个分类单独写页面:
1. 新建通用分类展示页面
创建新文件menu_category_page.dart,代码如下,保留你原有渲染逻辑的同时新增JSON路径参数:
import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:material_design_icons_flutter/material_design_icons_flutter.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:hexcolor/hexcolor.dart'; import 'package:localize_and_translate/localize_and_translate.dart'; // 新增构造参数接收JSON路径 class MenuCategoryPage extends StatelessWidget { const MenuCategoryPage({super.key, required this.jsonPath}); // 外部传入的对应分类JSON文件路径 final String jsonPath; @override Widget build(BuildContext context) { var screenHeight = MediaQuery.of(context).size.height; var screenWidth = MediaQuery.of(context).size.width; Future<List<Widget>> createList() async { List<Widget> items = <Widget>[]; // 这里改用传入的jsonPath加载对应文件 String dataString = await rootBundle.loadString(translator.translate(jsonPath)); List<dynamic> dataJSON = jsonDecode(dataString); dataJSON.forEach((object) { String finalString = ""; List<dynamic> dataList = object["placeItems"]; dataList.forEach((item) { finalString = finalString + item + " | "; }); items.add(Padding( padding: EdgeInsets.all(2.0), child: Container( decoration: BoxDecoration( color: Color.fromRGBO(255, 255, 255, 0.7), borderRadius: BorderRadius.all(Radius.circular(10.0)), boxShadow: [ BoxShadow( color: Colors.black12, spreadRadius: 2.0, blurRadius: 5.0), ]), margin: EdgeInsets.all(5.0), child: Column( mainAxisSize: MainAxisSize.max, crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[ ClipRRect( child: Image.asset( object["placeImage"], fit: BoxFit.cover, width: 280, height: 180, ), ), SizedBox( width: 250, child: Padding( padding: const EdgeInsets.all(8.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[ Text( translator.translate(object["placeName"]), style: GoogleFonts.elMessiri( textStyle: TextStyle( fontSize: 15.0, color: Colors.black54)), ), Text( translator.translate(" ${object["minOrder"]} IQD"), style: TextStyle(fontSize: 12.0, color: Colors.black54), ) ], ), ), ) ], ), ), )); }); return items; } return Scaffold( appBar: AppBar( backgroundColor: HexColor("#242424"), leading: IconButton( icon: Icon(Icons.arrow_back_ios), iconSize: 20.0, onPressed: () { Navigator.pop(context); }, ), title: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Image.asset( "assets/images/logo.png", fit: BoxFit.contain, height: 40, ), ], ), ), body: SafeArea( child: SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.center, mainAxisSize: MainAxisSize.min, children: <Widget>[ Container( decoration: BoxDecoration( image: DecorationImage( image: AssetImage("assets/images/backg.png"), fit: BoxFit.cover, ), ), height: 3000, width: screenWidth, child: FutureBuilder<List<Widget>>( initialData: [Text("")], future: createList(), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) return Text("Loading"); if (snapshot.hasError) { return Text("Error ${snapshot.error}"); } if (snapshot.hasData) { return Padding( padding: EdgeInsets.all(8.0), child: GridView.count( childAspectRatio: 1, crossAxisCount: 2, shrinkWrap: true, physics: NeverScrollableScrollPhysics(), children: [ ...?snapshot.data, ], )); } else { return CircularProgressIndicator(); } }), ) ], ), )), floatingActionButton: FloatingActionButton( onPressed: () { Navigator.push( context, MaterialPageRoute(builder: (context) => About()), ); }, backgroundColor: Colors.black, child: Icon( MdiIcons.information, color: Colors.white, )), ); } }
2. 修改首页跳转逻辑
调整首页中点击分类的跳转代码,传递对应分类的JSON路径即可:
首先在首页顶部引入通用页,删掉原有冗余页面的引入:
import 'package:menu_app/menu_category_page.dart'; // 删除原来的hotDrinks.dart、coldDrinks.dart引入
然后修改两个分类的点击事件:
// 热饮分类点击事件 onTap: () { Navigator.push( context, MaterialPageRoute(builder: (context) => const MenuCategoryPage(jsonPath: "assets/hotDrinks.json")), ); }, // 冷饮分类点击事件 onTap: () { Navigator.push( context, MaterialPageRoute(builder: (context) => const MenuCategoryPage(jsonPath: "assets/coldDrinks.json")), ); },
注意事项
- 后续新增甜点、餐食等品类,只需要在首页新增对应入口,传递对应JSON路径即可,无需重复创建页面
- 确保所有JSON文件路径都已在
pubspec.yaml的assets节点中注册 - 如果需要为不同分类定制标题、背景等样式,只需在通用页的构造函数中新增对应参数传递即可
内容的提问来源于stack exchange,提问作者sara97
相关产品推荐
相关产品推荐

