如何从本地 json 文件中获取数据并在 Flutter 中创建网格视图?

How can I get data from a local json file and create a gridview in Flutter?

我正在尝试用土耳其语制作一个教育应用程序,我想在我的主页上列出这些主题。我创建了我的主页草图,我想通过从本地 json 文件中获取名为“konuBasligi”的部分来打印卡片中的文本。

在分享代码之前,我想与您分享现有的设计和json文件:

{
    "bende": {
        "dersler": [{
            "id": 0,
            "dersAdi": "Türkçe"
        }, {
            "id": 1,
            "dersAdi": "Matematik"
        }, {
            "id": 2,
            "dersAdi": "Tarih",
            "konular": [{
                "konuId": 0,
                "konuBasligi": "İslamiyet Öncesi Türk Tarihi",
                "altkonular": [{
                    "altKonuId": 0,
                    "altKonuBasligi": "Giriş",
                    "basliklar": [{
                        "baslikId": 0,
                        "baslikAdi": "Türk Adının Anlamı"
                    }, {
                        "baslikId": 1,
                        "baslikAdi": "İlk Yerleşim Yerleri"
                    }, {
                        "baslikId": 2,
                        "baslikAdi": "Göçler"
                    }]
                }, {
                    "altKonuId": 1,
                    "altKonuBasligi": "İlk Türk Toplulukları ve Devletleri",
                    "basliklar": [{
                        "baslikId": 0,
                        "baslikAdi": "İskitler"
                    }, {
                        "baslikId": 1,
                        "baslikAdi": "Asya Hun Devleti"
                    }, {
                        "baslikId": 2,
                        "baslikAdi": "Avrupa Hun Devleti"
                    }]
                }, {
                    "altKonuId": 2,
                    "altKonuBasligi": "Diğer Türk Toplulukları ve Devletleri",
                    "basliklar": [{
                        "baslikId": 0,
                        "baslikAdi": "Avatarlar"
                    }, {
                        "baslikId": 1,
                        "baslikAdi": "Karluklar"
                    }, {
                        "baslikId": 2,
                        "baslikAdi": "Kırgızlar"
                    }]
                }, {
                    "altKonuId": 3,
                    "altKonuBasligi": "Kültür ve Medeniyet",
                    "basliklar": [{
                        "baslikId": 0,
                        "baslikAdi": "Hükümdarlar"
                    }, {
                        "baslikId": 1,
                        "baslikAdi": "Devlet Yönetimi"
                    }, {
                        "baslikId": 2,
                        "baslikAdi": "Ordu"
                    }]
                }]
            }, {
                "konuId": 1,
                "konuBasligi": "İlk Türk İslam Devletleri"
            }, {
                "konuId": 2,
                "konuBasligi": "Türkiye Tarihi"
            }, {
                "konuId": 3,
                "konuBasligi": "Osmanlı Tarihi"
            }, {
                "konuId": 4,
                "konuBasligi": "Kurtuluş Savaşı"
            }, {
                "konuId": 5,
                "konuBasligi": "Çağdaş Türk ve Dünya Tarihi"
            }]
        }, {
            "id": 3,
            "dersAdi": "Coğrafya"
        }, {
            "id": 4,
            "dersAdi": "Vatandaşlık"
        }, {
            "id": 5,
            "dersAdi": "Genel Kültür"
        }, {
            "id": 6,
            "dersAdi": "Program Geliştirme"
        }, {
            "id": 7,
            "dersAdi": "Rehberlik ve Özel Eğitim"
        }, {
            "id": 8,
            "dersAdi": "Öğretim Yöntem ve Teknikleri"
        }, {
            "id": 9,
            "dersAdi": "Ölçme ve Değerlendirme"
        }, {
            "id": 10,
            "dersAdi": "Öğrenme Psikolojisi"
        }, {
            "id": 11,
            "dersAdi": "Gelişim Psikolojisi"
        }]
    }
}

我想我使用“FutureBuilder”和“DefaultAssetBundle”从我观看的视频和阅读的文章中读取了数据,但我卡在了“Gridview.count”中的“children”部分。我无法自己改编,因为他们通常使用“Listview.builder”。

我分享的设计图片的代码包含了太多的文件,比如“screens”,“utils”。为此,我创建了一个文件,其中仅包含与我的问题相关的部分,其内容如下:

import 'dart:convert';
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());

class MyApp extends StatelessWidget { 
  const MyApp({Key? key}) : super(key: key);

@override
Widget build(BuildContext context) {
  return MaterialApp(
    title: 'Test',
    home: Scaffold(
    appBar: AppBar(
      title: const Text('Gridview From JSON'),
    ),

    body: FutureBuilder(
        future: DefaultAssetBundle.of(context).loadString('data/veri.json'),
        builder: (context, snapshot) {
          var read = json.decode(snapshot.data.toString());
          return GridView.count(
            crossAxisCount: 2,
            padding:
                const EdgeInsets.only(left: 12.0, right: 12.0, top: 8.0),
            scrollDirection: Axis.vertical,
            childAspectRatio: 1,
            physics: const NeverScrollableScrollPhysics(),
            shrinkWrap: true,
            children: [
              Card(
                shape: RoundedRectangleBorder(
                    borderRadius: BorderRadius.circular(16)),
                clipBehavior: Clip.antiAlias,
                color: Colors.blue[200],
              ),
            ],
          );
        }),
  ),
);
}
}

提前感谢您的帮助...

实际上,在未来的构建器中尝试使用数据之前,您必须检查状态。试试这些 -

FutureBuilder(
   future: DefaultAssetBundle.of(context).loadString('data/veri.json'),
   builder: (ctx, snapshot) {
     // Checking if future is resolved
   if (snapshot.connectionState == ConnectionState.done) {
     // If we got an error
   if (snapshot.hasError) {
     return Center(
       child: Text(
        '${snapshot.error} occured',
        style: TextStyle(fontSize: 18),
       ),
    );
    
    // if we got our data
   } else if (snapshot.hasData) {
       // Extracting data from snapshot object
       var read = json.decode(snapshot.data.toString());
      return GridView.count(
        crossAxisCount: 2,
        padding:
            const EdgeInsets.only(left: 12.0, right: 12.0, top: 8.0),
        scrollDirection: Axis.vertical,
        childAspectRatio: 1,
        physics: const NeverScrollableScrollPhysics(),
        shrinkWrap: true,
        children: [
          Card(
            shape: RoundedRectangleBorder(
                borderRadius: BorderRadius.circular(16)),
            clipBehavior: Clip.antiAlias,
            color: Colors.blue[200],
          ),
        ],
      );
     }
  }

),

希望对您有所帮助。

您有两个选择:

第一个选项: 是继续使用 GridView.count() 而对于 children 你必须以任何方法迭代它们,也许 for循环或.map()方法。

假设您将显示从 JSON 文件中读取的 dersler,并且您已经创建了一个变量来指向它们,如下所示:

var read = json.decode(snapshot.data.toString());
final List dersler = read['dersler'];

现在您可以通过遍历数据生成 children,

使用 .map() 方法的示例:

children: dersler.map((item) {
    return Card(
        shape: RoundedRectangleBorder(
            borderRadius: BorderRadius.circular(16)),
            clipBehavior: Clip.antiAlias,
            color: Colors.blue[200],
        );
    }).toList(),

使用 for 循环的示例:

children: [
    for (int i = 0; i < dersler.length; i++)
        Card(
            shape: RoundedRectangleBorder(
            borderRadius: BorderRadius.circular(16)),
            clipBehavior: Clip.antiAlias,
            color: Colors.blue[200],
         )
    ],

第二个选项(建议): 是使用 GridView.builder() 而不是使用 GridView.count(),这会给您带来 [= 的奖励46=]将数据存入内存,也就是说只有当前在屏幕上可见的数据才会保留在内存中,这是Flutter开箱即用的一个很好的优化。

示例:

FutureBuilder(
    future: DefaultAssetBundle.of(context).loadString('data/veri.json'),
        builder: (context, snapshot) {
            var read = json.decode(snapshot.data.toString());
            final List dersler = read['dersler'];
            return GridView.builder(
              gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
                crossAxisCount: 2,
              ),
              padding: const EdgeInsets.only(left: 12.0, right: 12.0, top: 8.0),
              scrollDirection: Axis.vertical,
              physics: const NeverScrollableScrollPhysics(),
              shrinkWrap: true,
              itemCount: dersler.length,
              itemBuilder: (BuildContext context, int index) {
                return Card(
                  shape: RoundedRectangleBorder(
                      borderRadius: BorderRadius.circular(16)),
                  clipBehavior: Clip.antiAlias,
                  color: Colors.blue[200],
                );
              },
        );
    },
),

我刚刚在你的问题上花了一些时间来重现这个例子。
Step1:您需要将JSON转换为模型,这可以在https://app.quicktype.io/的帮助下完成并将其保存为model.dart

// model.dart
// To parse this JSON data, do
//
//     final reportData = reportDataFromJson(jsonString);

import 'dart:convert';

import 'package:flutter/material.dart';

ReportData reportDataFromJson(String str) =>
    ReportData.fromJson(json.decode(str));

String reportDataToJson(ReportData data) => json.encode(data.toJson());

class ReportData {
  ReportData({
    this.bende,
  });

  Bende? bende;

  factory ReportData.fromJson(Map<String, dynamic> json) => ReportData(
        bende: Bende.fromJson(json["bende"]),
      );

  Map<String, dynamic> toJson() => {
        "bende": bende!.toJson(),
      };
}

class Bende {
  Bende({
    this.dersler,
  });

  List<Dersler>? dersler;

  factory Bende.fromJson(Map<String, dynamic> json) => Bende(
        dersler:
            List<Dersler>.from(json["dersler"].map((x) => Dersler.fromJson(x))),
      );

  Map<String, dynamic> toJson() => {
        "dersler": List<dynamic>.from(dersler!.map((x) => x.toJson())),
      };
}

class Dersler {
  Dersler({
    this.id,
    this.dersAdi,
    this.konular,
  });

  int? id;
  String? dersAdi;
  List<Konular>? konular;

  factory Dersler.fromJson(Map<String, dynamic> json) => Dersler(
        id: json["id"],
        dersAdi: json["dersAdi"],
        konular: json["konular"] == null
            ? null
            : List<Konular>.from(
                json["konular"].map((x) => Konular.fromJson(x))),
      );

  Map<String, dynamic> toJson() => {
        "id": id,
        "dersAdi": dersAdi,
        "konular": konular == null
            ? null
            : List<dynamic>.from(konular!.map((x) => x.toJson())),
      };
}

class Konular {
  Konular({
    this.konuId,
    this.konuBasligi,
    this.altkonular,
  });

  int? konuId;
  String? konuBasligi;
  List<Altkonular>? altkonular;

  factory Konular.fromJson(Map<String, dynamic> json) => Konular(
        konuId: json["konuId"],
        konuBasligi: json["konuBasligi"],
        altkonular: json["altkonular"] == null
            ? null
            : List<Altkonular>.from(
                json["altkonular"].map((x) => Altkonular.fromJson(x))),
      );

  Map<String, dynamic> toJson() => {
        "konuId": konuId,
        "konuBasligi": konuBasligi,
        "altkonular": altkonular == null
            ? null
            : List<dynamic>.from(altkonular!.map((x) => x.toJson())),
      };
}

class Altkonular {
  Altkonular({
    this.altKonuId,
    this.altKonuBasligi,
    this.basliklar,
  });

  int? altKonuId;
  String? altKonuBasligi;
  List<Basliklar>? basliklar;

  factory Altkonular.fromJson(Map<String, dynamic> json) => Altkonular(
        altKonuId: json["altKonuId"],
        altKonuBasligi: json["altKonuBasligi"],
        basliklar: List<Basliklar>.from(
            json["basliklar"].map((x) => Basliklar.fromJson(x))),
      );

  Map<String, dynamic> toJson() => {
        "altKonuId": altKonuId,
        "altKonuBasligi": altKonuBasligi,
        "basliklar": List<dynamic>.from(basliklar!.map((x) => x.toJson())),
      };
}

class Basliklar {
  Basliklar({
    this.baslikId,
    this.baslikAdi,
  });

  int? baslikId;
  String? baslikAdi;

  factory Basliklar.fromJson(Map<String, dynamic> json) => Basliklar(
        baslikId: json["baslikId"],
        baslikAdi: json["baslikAdi"],
      );

  Map<String, dynamic> toJson() => {
        "baslikId": baslikId,
        "baslikAdi": baslikAdi,
      };
}

Step2: 创建一个class从模型中获取数据,类似于

class DataFromReport {
  static Future<ReportData> getDataLocally(BuildContext context) async {
    final assetBundle = DefaultAssetBundle.of(context);
    final data = await assetBundle.loadString('data/veri.json');
    final reportData = reportDataFromJson(data);
    return reportData;
  }
}

Step3: 创建一个方法从 ReportData

中获取“konuBasligi”列表
//getting list of konular from ReportData
List<String> getkonular(ReportData? data) {
  List<String> listkonular = [];
  //konular is not present in all dersler
  // so fist get the length of dersler
  int length = data?.bende?.dersler?.length ?? 0;
  for (var i = 0; i < length; i++) {
    final ders = data?.bende?.dersler?.elementAt(i);
    //now get the number of konular
    int length2 = ders?.konular?.length ?? 0;
    for (var j = 0; j < length2; j++) {
      final konu = ders?.konular?.elementAt(j);
      listkonular.add(konu?.konuBasligi ?? '');
      // print(konu?.konuBasligi);
    }
  }
  return listkonular;
}

Step4:最后使用FutureBuilder<ReportData>

在GridView中显示项目
FutureBuilder<ReportData>(
  future: DataFromReport.getDataLocally(context),
  builder: (context, snapshot) {
    final data = snapshot.data;
    final List<String> list = getkonular(data);
    return GridView.count(
        crossAxisCount: 2,
        padding: const EdgeInsets.only(
            left: 12.0, right: 12.0, top: 8.0),
        scrollDirection: Axis.vertical,
        childAspectRatio: 1,
        physics: const NeverScrollableScrollPhysics(),
        shrinkWrap: true,
        children: List.generate(list.length, (index) {
          return Card(
              shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.circular(16)),
              clipBehavior: Clip.antiAlias,
              color: Colors.blue[200],
              child: Center(
                  child: Text(list[index],
                      style: const TextStyle(
                        fontSize: 20,
                        color: Colors.white,
                      ))));
        }));
  }),

示例快照:

main.dart 完整代码。

import 'package:flutter/material.dart';
import 'package:get_local_json_data/model.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Test',
        home: Scaffold(
          appBar: AppBar(
            title: const Text('Gridview From JSON'),
          ),
          body: FutureBuilder<ReportData>(
              future: DataFromReport.getDataLocally(context),
              builder: (context, snapshot) {
                final data = snapshot.data;
                final List<String> list = getkonular(data);
                return GridView.count(
                    crossAxisCount: 2,
                    padding: const EdgeInsets.only(
                        left: 12.0, right: 12.0, top: 8.0),
                    scrollDirection: Axis.vertical,
                    childAspectRatio: 1,
                    physics: const NeverScrollableScrollPhysics(),
                    shrinkWrap: true,
                    children: List.generate(list.length, (index) {
                      return Card(
                          shape: RoundedRectangleBorder(
                              borderRadius: BorderRadius.circular(16)),
                          clipBehavior: Clip.antiAlias,
                          color: Colors.blue[200],
                          child: Center(
                              child: Text(list[index],
                                  style: const TextStyle(
                                    fontSize: 20,
                                    color: Colors.white,
                                  ))));
                    }));
              }),
        ));
  }
}

//getting list of konular from ReportData
List<String> getkonular(ReportData? data) {
  List<String> listkonular = [];
  //konular is not present in all dersler
  // so fist get the length of dersler
  int length = data?.bende?.dersler?.length ?? 0;
  for (var i = 0; i < length; i++) {
    final ders = data?.bende?.dersler?.elementAt(i);
    //now get the number of konular
    int length2 = ders?.konular?.length ?? 0;
    for (var j = 0; j < length2; j++) {
      final konu = ders?.konular?.elementAt(j);
      listkonular.add(konu?.konuBasligi ?? '');
      // print(konu?.konuBasligi);
    }
  }
  return listkonular;
}

class DataFromReport {
  static Future<ReportData> getDataLocally(BuildContext context) async {
    final assetBundle = DefaultAssetBundle.of(context);
    final data = await assetBundle.loadString('data/veri.json');
    final reportData = reportDataFromJson(data);
    return reportData;
  }
}

文件夹结构

希望对您有所帮助。