Flutter实战:如何关联JSON中的food与instruction类并实现页面跳转
Flutter 食物列表与制作说明跳转实现方案
需求说明
- 首页展示带跳转功能的食物名称列表;
- 点击食物名称跳转到详情页,展示该食物对应的制作说明,关联规则:
food->batters->batter.id与instruction->category字段值匹配。
JSON数据示例
{ "food": [ { "id": "0001", "name": "Cake", "batters": { "batter": [ { "id": "instruction_1002", "type": "Chocolate" } ] } }, { "id": "0002", "name": "Raised", "batters": { "batter": [ { "id": "instruction_1003", "type": "Blueberry" } ] } } ], "instruction": [ { "category": "instruction_1002", "content": "abc1234" }, { "category": "instruction_1003", "content": "def56789" } ] }
功能示意
- 食物列表页:呈现可点击的食物名称列表(如Cake、Raised);
- 制作说明页:展示对应食物的制作说明内容(如点击Cake后显示"abc1234")。
代码实现
1. 定义数据模型类
创建对应JSON结构的模型类,简化数据解析:
// 食物模型 class Food { final String id; final String name; final BatterGroup batters; Food({required this.id, required this.name, required this.batters}); // 从JSON解析Food对象 factory Food.fromJson(Map<String, dynamic> json) { return Food( id: json['id'], name: json['name'], batters: BatterGroup.fromJson(json['batters']), ); } } // 面糊组模型 class BatterGroup { final List<Batter> batter; BatterGroup({required this.batter}); factory BatterGroup.fromJson(Map<String, dynamic> json) { var batterList = json['batter'] as List; List<Batter> batterItems = batterList.map((i) => Batter.fromJson(i)).toList(); return BatterGroup(batter: batterItems); } } // 面糊模型 class Batter { final String id; final String type; Batter({required this.id, required this.type}); factory Batter.fromJson(Map<String, dynamic> json) { return Batter( id: json['id'], type: json['type'], ); } } // 制作说明模型 class Instruction { final String category; final String content; Instruction({required this.category, required this.content}); factory Instruction.fromJson(Map<String, dynamic> json) { return Instruction( category: json['category'], content: json['content'], ); } }
2. 首页(食物列表页)
实现食物列表展示与跳转逻辑:
import 'package:flutter/material.dart'; import 'instruction_page.dart'; import 'models.dart'; import 'dart:convert'; class FoodListPage extends StatefulWidget { const FoodListPage({super.key}); @override State<FoodListPage> createState() => _FoodListPageState(); } class _FoodListPageState extends State<FoodListPage> { late List<Food> foodList; late List<Instruction> instructionList; @override void initState() { super.initState(); _loadData(); } void _loadData() { // 模拟加载JSON数据,实际项目可从asset或网络读取 String jsonString = ''' { "food": [ { "id": "0001", "name": "Cake", "batters": { "batter": [ { "id": "instruction_1002", "type": "Chocolate" } ] } }, { "id": "0002", "name": "Raised", "batters": { "batter": [ { "id": "instruction_1003", "type": "Blueberry" } ] } } ], "instruction": [ { "category": "instruction_1002", "content": "abc1234" }, { "category": "instruction_1003", "content": "def56789" } ] } '''; Map<String, dynamic> data = jsonDecode(jsonString); var foodJsonList = data['food'] as List; foodList = foodJsonList.map((json) => Food.fromJson(json)).toList(); var instructionJsonList = data['instruction'] as List; instructionList = instructionJsonList.map((json) => Instruction.fromJson(json)).toList(); } // 根据instructionId匹配对应说明内容 String? _getInstructionContent(String instructionId) { Instruction? instruction = instructionList.firstWhere( (inst) => inst.category == instructionId, orElse: () => Instruction(category: '', content: ''), ); return instruction.content.isNotEmpty ? instruction.content : null; } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('食物列表')), body: ListView.builder( itemCount: foodList.length, itemBuilder: (context, index) { Food food = foodList[index]; // 取第一个面糊ID作为关联标识(可根据需求调整多面糊场景逻辑) String instructionId = food.batters.batter.first.id; return InkWell( onTap: () { String? content = _getInstructionContent(instructionId); Navigator.push( context, MaterialPageRoute( builder: (context) => InstructionPage( foodName: food.name, content: content ?? '暂无制作说明', ), ), ); }, child: ListTile( title: Text(food.name), trailing: const Icon(Icons.arrow_forward_ios), ), ); }, ), ); } }
3. 详情页(制作说明页)
展示对应食物的制作说明内容:
import 'package:flutter/material.dart'; class InstructionPage extends StatelessWidget { final String foodName; final String content; const InstructionPage({ super.key, required this.foodName, required this.content, }); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('$foodName 制作说明')), body: Padding( padding: const EdgeInsets.all(16.0), child: Text( content, style: const TextStyle(fontSize: 16), ), ), ); } }
4. 主入口文件
import 'package:flutter/material.dart'; import 'food_list_page.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( title: '食物制作说明', theme: ThemeData(primarySwatch: Colors.blue), home: const FoodListPage(), ); } }
注意事项
- 实际项目中建议将JSON数据放在
assets目录下,通过rootBundle.loadString读取,避免硬编码; - 若食物存在多个面糊,可扩展逻辑支持展示多个说明或选择默认项;
- 可添加异常处理,比如未匹配到说明时的友好提示。
内容的提问来源于stack exchange,提问作者Joven Dev
相关产品推荐
相关产品推荐

