You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 09:25:29