我希望在屏幕上查看来自 API 的食物数据,并显示营养详细信息

I want food data from an API to be viewed with nutrients detail in my screen

提问人:PlayzAhmed 提问时间:11/10/2023 最后编辑:Brian Tompsett - 汤莱恩PlayzAhmed 更新时间:11/10/2023 访问量:26

问:

当我点击食物时,我想查看应用程序加载的营养成分,然后给我一个空屏幕,如向下所述,我需要在屏幕上显示营养成分而不给出空。 这是我的详细信息屏幕,应在此处查看营养详细信息:

详细信息屏幕:

class DetailScreen extends StatefulWidget {
  final int id;
  DetailScreen(this.id);
  @override
  _DetailSreenState createState() => _DetailSreenState();

}

class _DetailSreenState extends State<DetailScreen> {

  FoodData? foodData;
  bool loading = true;
  @override
  void initState() {
    fetchData();
    super.initState();
  }
  Future<void> fetchData() async {
    try {
        var url = Uri.parse('https://api.nal.usda.gov/fdc/v1/food/${widget.id}?api_key=DEMO_KEY');
  var response = (await http.get(url));
  final decodedResponse = convert.jsonDecode(response.body);
  

    foodData = FoodData.fromMap(decodedResponse);
  
  setState(() {
    loading = false;
  });
    } catch (e) {
      print(e);
    }

}

  @override
  Widget build(BuildContext context) {
  return Scaffold(
    appBar:  AppBar(title: loading ? SizedBox.shrink(): Text("${foodData?.description}", style: TextStyle(fontSize: 20),),),
    body: Container(
      child: loading? CircularProgressIndicator():Column(
        children: [
          Text("Portion: per 100g", style: TextStyle(fontSize: 25),),
          Container(
            child: Expanded(
              child: ListView.builder(
                itemCount: foodData == null? 0: foodData?.foodNutrients.length,
                itemBuilder: (context , index){
                return Padding(
                  padding: const EdgeInsets.all(10.0),
                  child: Text("${foodData?.foodNutrients[index].nutrient.name}:"
                  "${foodData?.foodNutrients[index].amount}" 
                  "${foodData?.foodNutrients[index].amount == null ? "" : foodData?.foodNutrients[index].nutrient.unitName}", 
                  style: TextStyle(fontSize: 20, fontWeight: FontWeight.w600, color: Colors.black54), ),
                );
              }),
            ),
          )
        ],
      ),
    ),
  );
  }

}


这是我的食物模型文件

食品型号 :

FoodData foodDataFromJson(String str) => FoodData.fromJson(json.decode(str));

String foodDataToJson(FoodData data) => json.encode(data.toJson());

class FoodData {
    String? foodClass;
    String? description;
    List<FoodNutrient> foodNutrients;
    List<FoodAttribute> foodAttributes;
    String? foodCode;
    String? startDate;
    String? endDate;
    WweiaFoodCategory wweiaFoodCategory;
    String? dataType;
    String? fdcId;
    List<FoodPortion> foodPortions;
    String? publicationDate;
    List<InputFood> inputFoods;

    FoodData({
        required this.foodClass,
        required this.description,
        required this.foodNutrients,
        required this.foodAttributes,
        required this.foodCode,
        required this.startDate,
        required this.endDate,
        required this.wweiaFoodCategory,
        required this.dataType,
        required this.fdcId,
        required this.foodPortions,
        required this.publicationDate,
        required this.inputFoods,
    });

    FoodData copyWith({
        String? foodClass,
        String? description,
        List<FoodNutrient>? foodNutrients,
        List<FoodAttribute>? foodAttributes,
        String? foodCode,
        String? startDate,
        String? endDate,
        WweiaFoodCategory? wweiaFoodCategory,
        String? dataType,
        String? fdcId,
        List<FoodPortion>? foodPortions,
        String? publicationDate,
        List<InputFood>? inputFoods,
    }) => 
        FoodData(
            foodClass: foodClass ?? this.foodClass,
            description: description ?? this.description,
            foodNutrients: foodNutrients ?? this.foodNutrients,
            foodAttributes: foodAttributes ?? this.foodAttributes,
            foodCode: foodCode ?? this.foodCode,
            startDate: startDate ?? this.startDate,
            endDate: endDate ?? this.endDate,
            wweiaFoodCategory: wweiaFoodCategory ?? this.wweiaFoodCategory,
            dataType: dataType ?? this.dataType,
            fdcId: fdcId ?? this.fdcId,
            foodPortions: foodPortions ?? this.foodPortions,
            publicationDate: publicationDate ?? this.publicationDate,
            inputFoods: inputFoods ?? this.inputFoods,
        );

    factory FoodData.fromJson(Map<String, dynamic> json) => FoodData(
        foodClass: json["foodClass"],
        description: json["description"],
        foodNutrients: List<FoodNutrient>.from(json["foodNutrients"].map((x) => FoodNutrient.fromJson(x))),
        foodAttributes: List<FoodAttribute>.from(json["foodAttributes"].map((x) => FoodAttribute.fromJson(x))),
        foodCode: json["foodCode"],
        startDate: json["startDate"],
        endDate: json["endDate"],
        wweiaFoodCategory: WweiaFoodCategory.fromJson(json["wweiaFoodCategory"]),
        dataType: json["dataType"],
        fdcId: json["fdcId"].toString(),
        foodPortions: List<FoodPortion>.from(json["foodPortions"].map((x) => FoodPortion.fromJson(x))),
        publicationDate: json["publicationDate"],
        inputFoods: List<InputFood>.from(json["inputFoods"].map((x) => InputFood.fromJson(x))),
    );

    Map<String, dynamic> toJson() => {
        "foodClass": foodClass,
        "description": description,
        "foodNutrients": List<dynamic>.from(foodNutrients.map((x) => x.toJson())),
        "foodAttributes": List<dynamic>.from(foodAttributes.map((x) => x.toJson())),
        "foodCode": foodCode,
        "startDate": startDate,
        "endDate": endDate,
        "wweiaFoodCategory": wweiaFoodCategory.toJson(),
        "dataType": dataType,
        "fdcId": fdcId,
        "foodPortions": List<dynamic>.from(foodPortions.map((x) => x.toJson())),
        "publicationDate": publicationDate,
        "inputFoods": List<dynamic>.from(inputFoods.map((x) => x.toJson())),
    };

  static fromMap(decodedResponse) {}
}

class FoodAttribute {
    int id;
    String? name;
    String value;
    FoodAttributeType foodAttributeType;
    String? rank;

    FoodAttribute({
        required this.id,
        this.name,
        required this.value,
        required this.foodAttributeType,
        this.rank,
    });

    FoodAttribute copyWith({
        int? id,
        String? name,
        String? value,
        FoodAttributeType? foodAttributeType,
        String? rank,
    }) => 
        FoodAttribute(
            id: id ?? this.id,
            name: name ?? this.name,
            value: value ?? this.value,
            foodAttributeType: foodAttributeType ?? this.foodAttributeType,
            rank: rank ?? this.rank,
        );

    factory FoodAttribute.fromJson(Map<String, dynamic> json) => FoodAttribute(
        id: json["id"],
        name: json["name"],
        value: json["value"],
        foodAttributeType: FoodAttributeType.fromJson(json["foodAttributeType"]),
        rank: json["rank"].toString(),
    );

    Map<String, dynamic> toJson() => {
        "id": id,
        "name": name,
        "value": value,
        "foodAttributeType": foodAttributeType.toJson(),
        "rank": rank,
    };
}

class FoodAttributeType {
    int id;
    String name;
    String description;

    FoodAttributeType({
        required this.id,
        required this.name,
        required this.description,
    });

    FoodAttributeType copyWith({
        int? id,
        String? name,
        String? description,
    }) => 
        FoodAttributeType(
            id: id ?? this.id,
            name: name ?? this.name,
            description: description ?? this.description,
        );

    factory FoodAttributeType.fromJson(Map<String, dynamic> json) => FoodAttributeType(
        id: json["id"],
        name: json["name"],
        description: json["description"],
    );

    Map<String, dynamic> toJson() => {
        "id": id,
        "name": name,
        "description": description,
    };
}

class FoodNutrient {
    Type type;
    int id;
    Nutrient nutrient;
    double amount;

    FoodNutrient({
        required this.type,
        required this.id,
        required this.nutrient,
        required this.amount,
    });

    FoodNutrient copyWith({
        Type? type,
        int? id,
        Nutrient? nutrient,
        double? amount,
    }) => 
        FoodNutrient(
            type: type ?? this.type,
            id: id ?? this.id,
            nutrient: nutrient ?? this.nutrient,
            amount: amount ?? this.amount,
        );

    factory FoodNutrient.fromJson(Map<String, dynamic> json) => FoodNutrient(
        type: typeValues.map[json["type"]]!,
        id: json["id"],
        nutrient: Nutrient.fromJson(json["nutrient"]),
        amount: json["amount"]?.toDouble(),
    );

    Map<String, dynamic> toJson() => {
        "type": typeValues.reverse[type],
        "id": id,
        "nutrient": nutrient.toJson(),
        "amount": amount,
    };
}

class Nutrient {
    int id;
    String number;
    String name;
    String rank;
    String unitName;

    Nutrient({
        required this.id,
        required this.number,
        required this.name,
        required this.rank,
        required this.unitName,
    });

    Nutrient copyWith({
        int? id,
        String? number,
        String? name,
        String? rank,
        String? unitName,
    }) => 
        Nutrient(
            id: id ?? this.id,
            number: number ?? this.number,
            name: name ?? this.name,
            rank: rank ?? this.rank,
            unitName: unitName ?? this.unitName,
        );

    factory Nutrient.fromJson(Map<String, dynamic> json) => Nutrient(
        id: json["id"],
        number: json["number"],
        name: json["name"],
        rank: json["rank"].toString(),
        unitName: json["unitName"],
    );

    Map<String, dynamic> toJson() => {
        "id": id,
        "number": number,
        "name": name,
        "rank": rank,
        "unitName": unitNameValues.reverse[unitName],
    };
}

enum UnitName {
    G,
    KCAL,
    MG,
    UNIT_NAME_G
}

final unitNameValues = EnumValues({
    "g": UnitName.G,
    "kcal": UnitName.KCAL,
    "mg": UnitName.MG,
    "µg": UnitName.UNIT_NAME_G
});

enum Type {
    FOOD_NUTRIENT
}

final typeValues = EnumValues({
    "FoodNutrient": Type.FOOD_NUTRIENT
});

class FoodPortion {
    int id;
    MeasureUnit measureUnit;
    String modifier;
    String gramWeight;
    String sequenceNumber;
    String portionDescription;

    FoodPortion({
        required this.id,
        required this.measureUnit,
        required this.modifier,
        required this.gramWeight,
        required this.sequenceNumber,
        required this.portionDescription,
    });

    FoodPortion copyWith({
        int? id,
        MeasureUnit? measureUnit,
        String? modifier,
        String? gramWeight,
        String? sequenceNumber,
        String? portionDescription,
    }) => 
        FoodPortion(
            id: id ?? this.id,
            measureUnit: measureUnit ?? this.measureUnit,
            modifier: modifier ?? this.modifier,
            gramWeight: gramWeight ?? this.gramWeight,
            sequenceNumber: sequenceNumber ?? this.sequenceNumber,
            portionDescription: portionDescription ?? this.portionDescription,
        );

    factory FoodPortion.fromJson(Map<String, dynamic> json) => FoodPortion(
        id: json["id"],
        measureUnit: MeasureUnit.fromJson(json["measureUnit"]),
        modifier: json["modifier"],
        gramWeight: json["gramWeight"].toString(),
        sequenceNumber: json["sequenceNumber"].toString(),
        portionDescription: json["portionDescription"],
    );

    Map<String, dynamic> toJson() => {
        "id": id,
        "measureUnit": measureUnit.toJson(),
        "modifier": modifier,
        "gramWeight": gramWeight,
        "sequenceNumber": sequenceNumber,
        "portionDescription": portionDescription,
    };
}

class MeasureUnit {
    int id;
    String name;
    String abbreviation;

    MeasureUnit({
        required this.id,
        required this.name,
        required this.abbreviation,
    });

    MeasureUnit copyWith({
        int? id,
        String? name,
        String? abbreviation,
    }) => 
        MeasureUnit(
            id: id ?? this.id,
            name: name ?? this.name,
            abbreviation: abbreviation ?? this.abbreviation,
        );

    factory MeasureUnit.fromJson(Map<String, dynamic> json) => MeasureUnit(
        id: json["id"],
        name: json["name"],
        abbreviation: json["abbreviation"],
    );

    Map<String, dynamic> toJson() => {
        "id": id,
        "name": name,
        "abbreviation": abbreviation,
    };
}

class InputFood {
    int id;
    String unit;
    String portionDescription;
    String portionCode;
    String foodDescription;
    String sequenceNumber;
    String ingredientWeight;
    String ingredientCode;
    String ingredientDescription;
    String amount;

    InputFood({
        required this.id,
        required this.unit,
        required this.portionDescription,
        required this.portionCode,
        required this.foodDescription,
        required this.sequenceNumber,
        required this.ingredientWeight,
        required this.ingredientCode,
        required this.ingredientDescription,
        required this.amount,
    });

    InputFood copyWith({
        int? id,
        String? unit,
        String? portionDescription,
        String? portionCode,
        String? foodDescription,
        String? sequenceNumber,
        String? ingredientWeight,
        String? ingredientCode,
        String? ingredientDescription,
        String? amount,
    }) => 
        InputFood(
            id: id ?? this.id,
            unit: unit ?? this.unit,
            portionDescription: portionDescription ?? this.portionDescription,
            portionCode: portionCode ?? this.portionCode,
            foodDescription: foodDescription ?? this.foodDescription,
            sequenceNumber: sequenceNumber ?? this.sequenceNumber,
            ingredientWeight: ingredientWeight ?? this.ingredientWeight,
            ingredientCode: ingredientCode ?? this.ingredientCode,
            ingredientDescription: ingredientDescription ?? this.ingredientDescription,
            amount: amount ?? this.amount,
        );

    factory InputFood.fromJson(Map<String, dynamic> json) => InputFood(
        id: json["id"],
        unit: json["unit"],
        portionDescription: json["portionDescription"],
        portionCode: json["portionCode"],
        foodDescription: json["foodDescription"],
        sequenceNumber: json["sequenceNumber"].toString(),
        ingredientWeight: json["ingredientWeight"].toString(),
        ingredientCode: json["ingredientCode"].toString(),
        ingredientDescription: json["ingredientDescription"],
        amount: json["amount"],
    );

    Map<String, dynamic> toJson() => {
        "id": id,
        "unit": unit,
        "portionDescription": portionDescription,
        "portionCode": portionCode,
        "foodDescription": foodDescription,
        "sequenceNumber": sequenceNumber,
        "ingredientWeight": ingredientWeight,
        "ingredientCode": ingredientCode,
        "ingredientDescription": ingredientDescription,
        "amount": amount,
    };
}

class WweiaFoodCategory {
    String wweiaFoodCategoryCode;
    String wweiaFoodCategoryDescription;

    WweiaFoodCategory({
        required this.wweiaFoodCategoryCode,
        required this.wweiaFoodCategoryDescription,
    });

    WweiaFoodCategory copyWith({
        String? wweiaFoodCategoryCode,
        String? wweiaFoodCategoryDescription,
    }) => 
        WweiaFoodCategory(
            wweiaFoodCategoryCode: wweiaFoodCategoryCode ?? this.wweiaFoodCategoryCode,
            wweiaFoodCategoryDescription: wweiaFoodCategoryDescription ?? this.wweiaFoodCategoryDescription,
        );

    factory WweiaFoodCategory.fromJson(Map<String, dynamic> json) => WweiaFoodCategory(
        wweiaFoodCategoryCode: json["wweiaFoodCategoryCode"].toString(),
        wweiaFoodCategoryDescription: json["wweiaFoodCategoryDescription"].toString(),
    );

    Map<String, dynamic> toJson() => {
        "wweiaFoodCategoryCode": wweiaFoodCategoryCode,
        "wweiaFoodCategoryDescription": wweiaFoodCategoryDescription,
    };
}

class EnumValues<T> {
    Map<String, T> map;
    late Map<T, String> reverseMap;

    EnumValues(this.map);

    Map<T, String> get reverse {
        reverseMap = map.map((k, v) => MapEntry(v, k));
        return reverseMap;
    }
}

当我使用该应用程序时,我得到了 null:

When i use the app i got null

Android Flutter 飞镖

评论


答:

0赞 Surya 11/10/2023 #1

使用值通知程序更新屏幕,如下所示

详细信息屏幕

class DetailScreen extends StatefulWidget {
  final int id;
  DetailScreen(this.id);
  @override
  _DetailSreenState createState() => _DetailSreenState();
}

class _DetailSreenState extends State<DetailScreen> {
  FoodData? foodData;
  ValueNotifier<bool> loading = ValueNotifier(true);

  @override
  void initState() {
    fetchData();
    super.initState();
  }

  Future<void> fetchData() async {
    print("****** fetching Data *********");
    try {
      loading.value = true;
      var url = Uri.parse('https://api.nal.usda.gov/fdc/v1/food/${widget.id}?api_key=DEMO_KEY');
      var response = (await http.get(url));
      final decodedResponse = json.decode(response.body);
      foodData = FoodData.fromMap(decodedResponse);
      loading.value = false;
    } catch (e) {
      print("****** fetching Data error *********");
      print(e);
    }
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        home: ValueListenableBuilder<bool>(
            valueListenable: loading,
            builder: (context, loadingVal, _) {
              return Scaffold(
                appBar: AppBar(
                  title: loadingVal
                      ? SizedBox.shrink()
                      : Text(
                          "${foodData?.description}",
                          style: TextStyle(fontSize: 20),
                        ),
                ),
                body: Container(
                  child: loadingVal
                      ? CircularProgressIndicator()
                      : Column(
                          children: [
                            Text(
                              "Portion: per 100g",
                              style: TextStyle(fontSize: 25),
                            ),
                            Container(
                              child: Expanded(
                                child: ListView.builder(
                                    itemCount: foodData == null ? 0 : foodData?.foodNutrients.length,
                                    itemBuilder: (context, index) {
                                      return Padding(
                                        padding: const EdgeInsets.all(10.0),
                                        child: Text(
                                          "${foodData?.foodNutrients[index].nutrient.name}:"
                                          "${foodData?.foodNutrients[index].amount}"
                                          "${foodData?.foodNutrients[index].amount == null ? "" : foodData?.foodNutrients[index].nutrient.unitName}",
                                          style: TextStyle(fontSize: 20, fontWeight: FontWeight.w600, color: Colors.black54),
                                        ),
                                      );
                                    }),
                              ),
                            )
                          ],
                        ),
                ),
              );
            }));
  }
}

注 - 如果 api 中有空值,请确保您正在处理 null 检查并显示正确的屏幕