I am using nested JSON as below and try to display using listview. Now, stuck on how to create children listTile widget How to parse the JSON subMenu and display as listTile? Is there any other simple methods or available package?
{
"categories": [
{
"icon":"icon.png",
"menu":"Menu 1",
"subtitle": "Subtitle 1",
"subMenu": [
{
"icon":"icon.png",
"title": "Sub Menu 1",
"jsonFile": "test.json"
},
{
"icon":"icon.png",
"title": "Sub Menu 2",
"jsonFile": "test.json"
}]}]}]}
class ScreenCategory extends StatefulWidget {
const ScreenCategory({super.key});
@override
State<ScreenCategory> createState() => _ScreenCategoryState();
}
class _ScreenCategoryState extends State<ScreenCategory> {
late Future newGeneratedCategory;
@override
void initState() {
super.initState();
newGeneratedCategory = newGetCategory();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder(
future: newGeneratedCategory,
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.data == null) {
return const SafeArea(
child: Center(child: CircularProgressIndicator()),
);
} else {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
return DisplayMenuList(aMenuItem: snapshot.data[index]);
},
);
}
},
),
);
}
}
Future newGetCategory() async {
String jsonString = await loadJsonFromAssets(menuDB);
final jsonResponse = json.decode(jsonString);
List menuList = [];
for (var item in jsonResponse[category]) {
menuList.add(MenuItem(item["icon"], item["menu"], item["subtitle"], item["subMenu"]),
);
}
return (menuList);
}
class DisplayMenuList extends StatelessWidget {
final MenuItem aMenuItem;
const DisplayMenuList({super.key, required this.aMenuItem});
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: ExpansionTile(
title: Text(aMenuItem.menu),
subtitle: Text(aMenuItem.subtitle),
children: [
// Replace below with json data DisplaySubMenuList(?),
ListTile(
title: Text('Install Flutter SDK'),
onTap: () {print('hello 1');},
),
ListTile(
title: Text('Install Flutter SDK'),
onTap: () {print('hello 2');},
),
],
),
);
}
}
class MenuItem {
final String icon;
final String menu;
final String subtitle;
final List subMenu;
MenuItem(this.icon, this.menu, this.subtitle, this.subMenu);
}
class SubMenuItem {
final String icon;
final String title;
final String jsonFile;
SubMenuItem(this.icon, this.title, this.jsonFile);
}
Here's the full fixed code you can try:
import 'package:flutter/material.dart';
import 'dart:convert';
import 'package:flutter/services.dart' show rootBundle;
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(home: ScreenCategory());
}
}
class ScreenCategory extends StatefulWidget {
const ScreenCategory({super.key});
@override
State<ScreenCategory> createState() => _ScreenCategoryState();
}
class _ScreenCategoryState extends State<ScreenCategory> {
late Future<List<MenuItem>> newGeneratedCategory;
@override
void initState() {
super.initState();
newGeneratedCategory = newGetCategory();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder(
future: newGeneratedCategory,
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.data == null) {
return const SafeArea(
child: Center(child: CircularProgressIndicator()),
);
} else {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
return DisplayMenuList(aMenuItem: snapshot.data[index]);
},
);
}
},
),
);
}
}
Future<Map<String, dynamic>> loadJsonFromAssets(String path) async {
String jsonString = await rootBundle.loadString(path);
Map<String, dynamic> jsonMap = json.decode(jsonString);
return jsonMap;
}
String menuDB = "assets/myJson.json";
Future<List<MenuItem>> newGetCategory() async {
Map<String, dynamic> jsonResponse = await loadJsonFromAssets(menuDB);
List<MenuItem> menuList = [];
List<dynamic> categories = jsonResponse['categories'];
for (var item in categories) {
List<SubMenuItem> subMenuList = [];
if (item['subMenu'] != null) {
for (var sub in item['subMenu']) {
subMenuList.add(
SubMenuItem(sub['icon'], sub['title'], sub['jsonFile']),
);
}
}
menuList.add(
MenuItem(item['icon'], item['menu'], item['subtitle'], subMenuList),
);
}
return menuList;
}
class DisplayMenuList extends StatelessWidget {
final MenuItem aMenuItem;
const DisplayMenuList({super.key, required this.aMenuItem});
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: ExpansionTile(
title: Text(aMenuItem.menu),
subtitle: Text(aMenuItem.subtitle),
children: aMenuItem.subMenu.map((subItem) {
return ListTile(
title: Text(subItem.title),
subtitle: Text(subItem.jsonFile),
onTap: () {
print('Tapped: ${subItem.title}');
},
);
}).toList(),
),
);
}
}
class MenuItem {
final String icon;
final String menu;
final String subtitle;
final List<SubMenuItem> subMenu;
MenuItem(this.icon, this.menu, this.subtitle, this.subMenu);
}
class SubMenuItem {
final String icon;
final String title;
final String jsonFile;
SubMenuItem(this.icon, this.title, this.jsonFile);
}