简体   繁体   中英

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.

Before sharing the codes, I would like to share the existing design and json file with you:

{
    "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". I couldn't adapt it myself because they usually use "Listview.builder".

The code of the design image I shared contains too many files such as "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

// 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

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

//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>

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.

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.

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:

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:

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

Example using for loop:

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.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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