简体   繁体   English

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

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

I'm trying to make an educational application in Turkish and i want to list the topics on my homepage.我正在尝试用土耳其语制作教育应用程序,我想在我的主页上列出主题。 I created a sketch of my homepage and i want to print the texts inside the cards by taking the parts named "konuBasligi" from the local json file.我创建了主页的草图,我想通过从本地 json 文件中获取名为“konuBasligi”的部分来打印卡片内的文本。

Before sharing the codes, I would like to share the existing design and json file with you:在分享代码之前,我想和大家分享一下现有的设计和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"
        }]
    }
}

I think I read the data using "FutureBuilder" and "DefaultAssetBundle" from the video I watched and the articles I read, but I got stuck in the "children" part in "Gridview.count".我想我从观看的视频和阅读的文章中使用“FutureBuilder”和“DefaultAssetBundle”读取了数据,但我陷入了“Gridview.count”中的“children”部分。 I couldn't adapt it myself because they usually use "Listview.builder".我无法自己调整它,因为他们通常使用“Listview.builder”。

The code of the design image I shared contains too many files such as "screens", "utils".我分享的设计图片的代码包含太多的文件,例如“screens”、“utils”。 For this, I created a file with only the parts related to my question and its contents are as follows:为此,我创建了一个文件,其中仅包含与我的问题相关的部分,其内容如下:

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],
              ),
            ],
          );
        }),
  ),
);
}
}

Thank you in advance for your help...预先感谢您的帮助...

I Just spent some time on your question to recreate the example.我刚刚在您的问题上花了一些时间来重新创建示例。
Step1 : You need to convert the JSON to a model, which Can be done with the help of https://app.quicktype.io/ and save it as model.dart 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 : Create a class to get Data from the model, something like Step2 :创建一个类以从模型中获取数据,例如

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 : Create a method to get the list of "konuBasligi" from 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 : Finally display the items in GridView using FutureBuilder<ReportData> 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,
                      ))));
        }));
  }),

SnapShot of the Example:示例快照:
在此处输入图像描述

main.dart full code. 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;
  }
}

Folder Structure文件夹结构
在此处输入图像描述

Hope this will be helpful for you.希望这对您有所帮助。

Actually you have to check for state before trying to use data in future builder.实际上,在尝试在未来的构建器中使用数据之前,您必须检查状态。 Try these -试试这些——

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],
          ),
        ],
      );
     }
  }

),

Hope it helps.希望能帮助到你。

You have two options:你有两个选择:

First Option: is to continue using GridView.count() and for the children you have to just iterate on them in any method, maybe for loop or .map() method.第一个选项:是继续使用GridView.count()并且对于children ,您必须以任何方法迭代它们,可能for循环或.map()方法。

Let's say you will display the dersler read from the JSON file and you have created a variable to point on them like the following:假设您将显示从 JSON 文件中读取的dersler ,并且您已经创建了一个变量来指向它们,如下所示:

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

Now you can generate the children by iterating over the data,现在您可以通过迭代数据来生成孩子,

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

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

Example using for loop:使用for循环的示例:

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

Second Option (Suggested): is to use GridView.builder() instead of using GridView.count() which gives you a bonus of lazy-loading the data into memory, which means only the data that is currently visible on the screen would be held in the memory, which is a very good optimization made out of the box by Flutter.第二个选项(建议):是使用GridView.builder()而不是使用GridView.count()这给你一个延迟加载数据到内存的奖励,这意味着只有当前在屏幕上可见的数据才会是保存在内存中,这是 Flutter 开箱即用的一个非常好的优化。

Example:例子:

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],
                );
              },
        );
    },
),

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM